* [RFC Patch 0/1] Enhancements to 'trace' infrastructure @ 2008-04-15 11:14 K. Prasad 2008-04-15 11:26 ` [RFC Patch 1/1] debugfs_printk and debugfs_dump interface K. Prasad 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-15 11:14 UTC (permalink / raw) To: linux-kernel; +Cc: dwilder, mathieu.desnoyers, hunt Hi All, Please review the following patch which introduces two new interfaces to output data using 'trace' infrastructure. These interfaces can be used to print directly onto a debugfs mount. Since it uses 'trace' interface underneath the directory and file structures are as created by 'trace'. The proposed debugfs_* interfaces are meant to overcome the need to setup/tear-down 'trace' infrastructure by the user. In addition to this the patches help in: a) Printing out data into a debugfs mounted file without bothering about creating/re-using debugfs files, sizes of intermediate buffers, etc. (This is achieved through the functions init_trace_interface() and trace_exists()). b) Provide interfaces to do i)string output or ii)binary dump of data c) Tear-down of the trace infrastructure through a single function call using its parent directory name, and unmindful of the internal data structures such as 'struct trace_info'.(using trace_cleanup_all) d) The debugfs_printk_data may be further enhanced to provide features suh as the ability to invoke pre- and post- printing callback functions For e.g. A callback function to obtain a given lock before printing out a given data, etc. A quick look at samples/trace/fork_trace.c would help understand what is required to get data out using the 'trace' infrastructure (vs the proposed interfaces which have been exemplified in samples/trace/fork_new_trace.c). The patches are based against 2.6.25-rc8-mm1 and have been tested on an i386 machine. Thanks, K.Prasad ^ permalink raw reply [flat|nested] 14+ messages in thread
* [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-15 11:14 [RFC Patch 0/1] Enhancements to 'trace' infrastructure K. Prasad @ 2008-04-15 11:26 ` K. Prasad 2008-04-16 21:25 ` David Wilder 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-15 11:26 UTC (permalink / raw) To: linux-kernel; +Cc: dwilder, mathieu.desnoyers, hunt This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- include/linux/trace.h | 54 ++++++++++++ lib/trace.c | 183 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 98 +++++++++++++++++++++ 4 files changed, 331 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,30 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +93,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +114,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +131,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,6 +29,7 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); static int state_open(struct inode *inode, struct file *filp) @@ -99,9 +100,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +153,16 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + if (!temp) + return ERR_PTR(-ENOMEM); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,16 +171,49 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; +} + +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; } +EXPORT_SYMBOL_GPL(trace_exists); static int dropped_open(struct inode *inode, struct file *filp) { @@ -561,3 +610,127 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace_info/directories created under a + * parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf_(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data * dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch (dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if (!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if (!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, TRACE_FLIGHT_CHANNEL); + printk(KERN_INFO "Trace interface %s setup\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state != TRACE_RUNNING) + trace_start(ti); + } + return ti; +} + +/* + * debugfs_printk - A function to write into the debugfs mount 'directly' + * using 'trace' infrastructure + * @dpk - Structure containing info such as parent_dir and directory + * @format - String containing format string specifiers + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + ret = trace_printf_(ti, format, ap); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/* + * @output - Data that needs to be output + * @output_len - Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + int ret = 0; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + record = relay_reserve(ti->rchan, output_len); + if (record) + memcpy(record, output, output_len); + else + ret = -ENOMEM; + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,98 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2008 IBM Inc. + * + * K.Prasad <prasad@linux.vnet.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_new_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_new_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if (!dpk) + ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if (ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-15 11:26 ` [RFC Patch 1/1] debugfs_printk and debugfs_dump interface K. Prasad @ 2008-04-16 21:25 ` David Wilder 2008-04-21 12:43 ` K. Prasad 0 siblings, 1 reply; 14+ messages in thread From: David Wilder @ 2008-04-16 21:25 UTC (permalink / raw) To: prasad; +Cc: linux-kernel, mathieu.desnoyers, hunt K. Prasad wrote: > > + > +struct debugfs_printk_data { > + char *parent_dir; > + char *dir; > + int exists; > + int buf_size; > + int sub_buf_size; > +}; How about adding a "flags" field here to hold the trace channel flags. Pass the flags through to trace_setup(). This way the caller can control the trace options. Add a description of debugfs_printk() and debugfs_dump() to Documentation/trace.txt. ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-16 21:25 ` David Wilder @ 2008-04-21 12:43 ` K. Prasad 2008-04-21 17:14 ` Randy Dunlap 2008-04-24 21:23 ` David Wilder 0 siblings, 2 replies; 14+ messages in thread From: K. Prasad @ 2008-04-21 12:43 UTC (permalink / raw) To: David Wilder; +Cc: linux-kernel, mathieu.desnoyers, hunt, michaele, dave On Wed, Apr 16, 2008 at 02:25:18PM -0700, David Wilder wrote: > K. Prasad wrote: > > > > >+ > >+struct debugfs_printk_data { > >+ char *parent_dir; > >+ char *dir; > >+ int exists; > >+ int buf_size; > >+ int sub_buf_size; > >+}; > > How about adding a "flags" field here to hold the trace channel flags. > Pass the flags through to trace_setup(). This way the caller can > control the trace options. > > Add a description of debugfs_printk() and debugfs_dump() to > Documentation/trace.txt. Hi David, Thanks for your comments. I have added a flags field to struct debugfs_printk_data (defaulting to TRACE_FLIGHT_CHANNEL) and updated the documentation apart from a minor name change (trace_printf). Please review the changes. Thanks, K.Prasad This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- Documentation/trace.txt | 21 ++++ include/linux/trace.h | 55 +++++++++++ lib/trace.c | 196 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ 5 files changed, 365 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,31 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; + unsigned long flags; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +94,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +115,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +132,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,7 +29,9 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); +static DEFINE_SPINLOCK(trace_lock); static int state_open(struct inode *inode, struct file *filp) { @@ -99,9 +101,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +154,14 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,16 +170,49 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; +} + +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; } +EXPORT_SYMBOL_GPL(trace_exists); static int dropped_open(struct inode *inode, struct file *filp) { @@ -561,3 +609,141 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace_info/directories created under a + * parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data *dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch(dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if(!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if(!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + if(!dpk->flags) + dpk->flags = TRACE_FLIGHT_CHANNEL; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, dpk->flags); + printk(KERN_INFO "Trace interface %s setup through " + "debugfs_printk\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state != TRACE_RUNNING) { + trace_start(ti); + } + } + return ti; +} + +/* + * debugfs_printk - A function to write into the debugfs mount 'directly' + * using 'trace' infrastructure + * @dpk - Structure containing info such as parent_dir and directory + * @format - String containing format string specifiers + * @ap - List of arguments + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + unsigned long flags; + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + /* Take an RCU Lock over the trace_info state */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + ret = trace_printf(ti, format, ap); + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/* + * debugfs_printk - A function to write into the debugfs mount 'directly' + * using 'trace' infrastructure + * @dpk - Structure containing info such as parent_dir and directory + * @output - Data that needs to be output + * @output_len - Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + record = relay_reserve(ti->rchan, output_len); + if (record) + memcpy(record, output, output_len); + else + return -ENOMEM; + rcu_read_unlock(); + + return 0; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,97 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2007 IBM Inc. + * + * David Wilder <dwilder@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if(!dpk) ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if(ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt =================================================================== --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt @@ -150,6 +150,27 @@ The steps a kernel data provider takes t 5) Destroy the trace channel and underlying relay channel - trace_cleanup(). +Alternatively the user may choose to make use of two new interfaces +debugfs_printk() and debugfs_dump() to setup trace interface and +trace_cleanup_all() to tear-down the same. + +Steps to use: +1) Create and populate an instance of debugfs_printk_data structure. The fields + parent_dir and dir are mandatory. The fields buf_size, sub_buf_size and flags + are optional and will take default values if not populated. The field + 'exists' is for the trace infrastructure to use. +2) Default values for buf_size, sub_buf_size and flags are 4096, 40 and + TRACE_FLIGHT_CHANNEL respectively. +3) Use debugfs_dump() to output binary data which may be acted upon by a + high-level program (say dumping a structure). debugfs_printk() can be used + for string output. Pass a pointer to the instance of debugfs_printk_data + structure to these functions along with other parameters. The output from + these functions can be found at + <debugfs_mount>/<parent_dir>/<dir>/trace<0..n>. +4) trace_cleanup_all() for a given parent directory will cleanup and remove all + trace directories created under the specified directory. +5) Sample code for the same can be found in samples/trace/fork_new_trace.c + Kernel Configuration -------------------- To use trace, configure your kernel with CONFIG_TRACE=y. Trace depends on ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-21 12:43 ` K. Prasad @ 2008-04-21 17:14 ` Randy Dunlap 2008-04-22 5:22 ` K. Prasad 2008-04-24 21:23 ` David Wilder 1 sibling, 1 reply; 14+ messages in thread From: Randy Dunlap @ 2008-04-21 17:14 UTC (permalink / raw) To: prasad; +Cc: David Wilder, linux-kernel, mathieu.desnoyers, hunt, michaele, dave On Mon, 21 Apr 2008 18:13:29 +0530 K. Prasad wrote: > This patch introduces two new interfaces called debugfs_printk and > debugfs_dump which can be used to print to the debugfs mount directly. > It uses the 'trace' infrastructure underneath and is a patch over it. > A sample file is also created to demonstrate its ease of use. > > Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> > --- > Documentation/trace.txt | 21 ++++ > include/linux/trace.h | 55 +++++++++++ > lib/trace.c | 196 +++++++++++++++++++++++++++++++++++++++-- > samples/trace/Makefile | 2 > samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ > 5 files changed, 365 insertions(+), 6 deletions(-) > Index: linux-2.6.25-rc8-mm1/lib/trace.c > =================================================================== > --- linux-2.6.25-rc8-mm1.orig/lib/trace.c > +++ linux-2.6.25-rc8-mm1/lib/trace.c > @@ -561,3 +609,141 @@ void trace_cleanup(struct trace_info *tr > kfree(trace); > } > EXPORT_SYMBOL_GPL(trace_cleanup); > + > +/** > + * trace_cleanup_all - Removes all trace_info/directories created under a > + * parent_dir kernel-doc requires the "function name - description" to be on one line. You could change the *<tab> to be *<space(s)>. > + * @parent_dir: Name of the parent directory > + */ > +void trace_cleanup_all(const char *parent_dir) > +{ > + struct list_head *pos, *pos_temp; > + struct trace_dir *temp; > + > + list_for_each_safe(pos, pos_temp, &trace_dirs) { > + temp = list_entry(pos, struct trace_dir, trace_dir_list); > + if (!strcmp(parent_dir, temp->trace_root->d_iname)) > + trace_cleanup(temp->ti); > + } > +} > +EXPORT_SYMBOL_GPL(trace_cleanup_all); > + ... > + > +/* > + * debugfs_printk - A function to write into the debugfs mount 'directly' > + * using 'trace' infrastructure > + * @dpk - Structure containing info such as parent_dir and directory > + * @format - String containing format string specifiers > + * @ap - List of arguments This one isn't quite kernel-doc notation, but it's very close to it, and it should be kernel-doc since it's an exported symbol. So it needs the following changes: - begin with /** - put function name + short description on one line - use "@dpk: <description>" for function parameters (not "-") > + */ > +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) > +{ > + int ret; > + struct trace_info *ti; > + va_list(ap); > + unsigned long flags; > + > + va_start(ap, format); > + > + ti = init_trace_interface(dpk); > + > + /* Now do the actual printing */ > + /* Take an RCU Lock over the trace_info state */ > + rcu_read_lock(); > + /* Take a spinlock for the global buffer used by relay */ > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > + spin_lock_irqsave(&trace_lock, flags); > + ret = trace_printf(ti, format, ap); > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > + spin_unlock_irqrestore(&trace_lock, flags); > + rcu_read_unlock(); > + > + va_end(ap); > + return ret; > +} > +EXPORT_SYMBOL(debugfs_printk); > + > +/* > + * debugfs_printk - A function to write into the debugfs mount 'directly' > + * using 'trace' infrastructure > + * @dpk - Structure containing info such as parent_dir and directory > + * @output - Data that needs to be output > + * @output_len - Length of the output data Use kernel-doc notation. Same comments as above. > + */ > +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > + const int output_len) > +{ > + struct trace_info *ti; > + char *record; > + > + ti = init_trace_interface(dpk); > + > + /* Now do the actual printing */ > + rcu_read_lock(); > + record = relay_reserve(ti->rchan, output_len); > + if (record) > + memcpy(record, output, output_len); > + else > + return -ENOMEM; > + rcu_read_unlock(); > + > + return 0; > +} > +EXPORT_SYMBOL(debugfs_dump); > Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt > =================================================================== > --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt > +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt > @@ -150,6 +150,27 @@ The steps a kernel data provider takes t > 5) Destroy the trace channel and underlying relay channel - > trace_cleanup(). > > +Alternatively the user may choose to make use of two new interfaces two new interfaces -- > +debugfs_printk() and debugfs_dump() to setup trace interface and and debugfs_dump() -- to setup trace interfaces and > +trace_cleanup_all() to tear-down the same. > + > +Steps to use: --- ~Randy ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-21 17:14 ` Randy Dunlap @ 2008-04-22 5:22 ` K. Prasad 2008-04-22 14:53 ` Randy Dunlap 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-22 5:22 UTC (permalink / raw) To: Randy Dunlap Cc: prasad, David Wilder, linux-kernel, mathieu.desnoyers, hunt, michaele, dave On Mon, Apr 21, 2008 at 10:14:03AM -0700, Randy Dunlap wrote: > On Mon, 21 Apr 2008 18:13:29 +0530 K. Prasad wrote: > > > This patch introduces two new interfaces called debugfs_printk and > > debugfs_dump which can be used to print to the debugfs mount directly. > > It uses the 'trace' infrastructure underneath and is a patch over it. > > A sample file is also created to demonstrate its ease of use. > > > > Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> > > --- > > Documentation/trace.txt | 21 ++++ > > include/linux/trace.h | 55 +++++++++++ > > lib/trace.c | 196 +++++++++++++++++++++++++++++++++++++++-- > > samples/trace/Makefile | 2 > > samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ > > 5 files changed, 365 insertions(+), 6 deletions(-) > > > Index: linux-2.6.25-rc8-mm1/lib/trace.c > > =================================================================== > > --- linux-2.6.25-rc8-mm1.orig/lib/trace.c > > +++ linux-2.6.25-rc8-mm1/lib/trace.c > > @@ -561,3 +609,141 @@ void trace_cleanup(struct trace_info *tr > > kfree(trace); > > } > > EXPORT_SYMBOL_GPL(trace_cleanup); > > + > > +/** > > + * trace_cleanup_all - Removes all trace_info/directories created under a > > + * parent_dir > > kernel-doc requires the "function name - description" to be on one line. > You could change the *<tab> to be *<space(s)>. > > > + * @parent_dir: Name of the parent directory > > + */ > > +void trace_cleanup_all(const char *parent_dir) > > +{ > > + struct list_head *pos, *pos_temp; > > + struct trace_dir *temp; > > + > > + list_for_each_safe(pos, pos_temp, &trace_dirs) { > > + temp = list_entry(pos, struct trace_dir, trace_dir_list); > > + if (!strcmp(parent_dir, temp->trace_root->d_iname)) > > + trace_cleanup(temp->ti); > > + } > > +} > > +EXPORT_SYMBOL_GPL(trace_cleanup_all); > > + > ... > > + > > +/* > > + * debugfs_printk - A function to write into the debugfs mount 'directly' > > + * using 'trace' infrastructure > > + * @dpk - Structure containing info such as parent_dir and directory > > + * @format - String containing format string specifiers > > + * @ap - List of arguments > > This one isn't quite kernel-doc notation, but it's very close to it, > and it should be kernel-doc since it's an exported symbol. > So it needs the following changes: > > - begin with /** > - put function name + short description on one line > - use "@dpk: <description>" for function parameters (not "-") > > > + */ > > +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) > > +{ > > + int ret; > > + struct trace_info *ti; > > + va_list(ap); > > + unsigned long flags; > > + > > + va_start(ap, format); > > + > > + ti = init_trace_interface(dpk); > > + > > + /* Now do the actual printing */ > > + /* Take an RCU Lock over the trace_info state */ > > + rcu_read_lock(); > > + /* Take a spinlock for the global buffer used by relay */ > > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > > + spin_lock_irqsave(&trace_lock, flags); > > + ret = trace_printf(ti, format, ap); > > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > > + spin_unlock_irqrestore(&trace_lock, flags); > > + rcu_read_unlock(); > > + > > + va_end(ap); > > + return ret; > > +} > > +EXPORT_SYMBOL(debugfs_printk); > > + > > +/* > > + * debugfs_printk - A function to write into the debugfs mount 'directly' > > + * using 'trace' infrastructure > > + * @dpk - Structure containing info such as parent_dir and directory > > + * @output - Data that needs to be output > > + * @output_len - Length of the output data > > Use kernel-doc notation. Same comments as above. > > > + */ > > +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > > + const int output_len) > > +{ > > + struct trace_info *ti; > > + char *record; > > + > > + ti = init_trace_interface(dpk); > > + > > + /* Now do the actual printing */ > > + rcu_read_lock(); > > + record = relay_reserve(ti->rchan, output_len); > > + if (record) > > + memcpy(record, output, output_len); > > + else > > + return -ENOMEM; > > + rcu_read_unlock(); > > + > > + return 0; > > +} > > +EXPORT_SYMBOL(debugfs_dump); > > > Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt > > =================================================================== > > --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt > > +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt > > @@ -150,6 +150,27 @@ The steps a kernel data provider takes t > > 5) Destroy the trace channel and underlying relay channel - > > trace_cleanup(). > > > > +Alternatively the user may choose to make use of two new interfaces > > two new interfaces -- > > > +debugfs_printk() and debugfs_dump() to setup trace interface and > > and debugfs_dump() -- to setup trace interfaces and > > > +trace_cleanup_all() to tear-down the same. > > + > > +Steps to use: > > > --- > ~Randy Thanks for the review Randy, and teaching me a thing of two about kernel-doc notations! Please find the revised patch below. This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- Documentation/trace.txt | 21 ++++ include/linux/trace.h | 55 +++++++++++ lib/trace.c | 193 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ 5 files changed, 362 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,31 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; + unsigned long flags; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +94,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +115,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +132,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,7 +29,9 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); +static DEFINE_SPINLOCK(trace_lock); static int state_open(struct inode *inode, struct file *filp) { @@ -99,9 +101,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +154,14 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,16 +170,49 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; +} + +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; } +EXPORT_SYMBOL_GPL(trace_exists); static int dropped_open(struct inode *inode, struct file *filp) { @@ -561,3 +609,138 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace directories under a parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data *dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch(dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if(!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if(!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + if(!dpk->flags) + dpk->flags = TRACE_FLIGHT_CHANNEL; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, dpk->flags); + printk(KERN_INFO "Trace interface %s setup through " + "debugfs_printk\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state != TRACE_RUNNING) { + trace_start(ti); + } + } + return ti; +} + +/** + * debugfs_printk - Output a string to debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @format: String containing format string specifiers + * @ap: List of arguments + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + unsigned long flags; + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + /* Take an RCU Lock over the trace_info state */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + ret = trace_printf(ti, format, ap); + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/** + * debugfs_printk - Output binary into debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @output: Data that needs to be output + * @output_len: Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + record = relay_reserve(ti->rchan, output_len); + if (record) + memcpy(record, output, output_len); + else + return -ENOMEM; + rcu_read_unlock(); + + return 0; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,97 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2007 IBM Inc. + * + * David Wilder <dwilder@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if(!dpk) ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if(ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt =================================================================== --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt @@ -150,6 +150,27 @@ The steps a kernel data provider takes t 5) Destroy the trace channel and underlying relay channel - trace_cleanup(). +Alternatively the user may choose to make use of two new interfaces -- +debugfs_printk() and debugfs_dump() -- to setup trace interface and +trace_cleanup_all() to tear-down the same. + +Steps to use: +1) Create and populate an instance of debugfs_printk_data structure. The fields + parent_dir and dir are mandatory. The fields buf_size, sub_buf_size and flags + are optional and will take default values if not populated. The field + 'exists' is for the trace infrastructure to use. +2) Default values for buf_size, sub_buf_size and flags are 4096, 40 and + TRACE_FLIGHT_CHANNEL respectively. +3) Use debugfs_dump() to output binary data which may be acted upon by a + high-level program (say dumping a structure). debugfs_printk() can be used + for string output. Pass a pointer to the instance of debugfs_printk_data + structure to these functions along with other parameters. The output from + these functions can be found at + <debugfs_mount>/<parent_dir>/<dir>/trace<0..n>. +4) trace_cleanup_all() for a given parent directory will cleanup and remove all + trace directories created under the specified directory. +5) Sample code for the same can be found in samples/trace/fork_new_trace.c + Kernel Configuration -------------------- To use trace, configure your kernel with CONFIG_TRACE=y. Trace depends on ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-22 5:22 ` K. Prasad @ 2008-04-22 14:53 ` Randy Dunlap 2008-04-23 7:59 ` K. Prasad 0 siblings, 1 reply; 14+ messages in thread From: Randy Dunlap @ 2008-04-22 14:53 UTC (permalink / raw) To: prasad; +Cc: David Wilder, linux-kernel, mathieu.desnoyers, hunt, michaele, dave K. Prasad wrote: > This patch introduces two new interfaces called debugfs_printk and > debugfs_dump which can be used to print to the debugfs mount directly. > It uses the 'trace' infrastructure underneath and is a patch over it. > A sample file is also created to demonstrate its ease of use. > > Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> > --- > Documentation/trace.txt | 21 ++++ > include/linux/trace.h | 55 +++++++++++ > lib/trace.c | 193 +++++++++++++++++++++++++++++++++++++++-- > samples/trace/Makefile | 2 > samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ > 5 files changed, 362 insertions(+), 6 deletions(-) > + > +/** > + * debugfs_printk - Output binary into debugfs mount 'directly' using 'trace' Oops. This is the debugfs_dump() function. Otherwise it looks good. Thanks. > + * @dpk: Structure containing info such as parent_dir and directory > + * @output: Data that needs to be output > + * @output_len: Length of the output data > + */ > +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > + const int output_len) > +{ -- ~Randy ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-22 14:53 ` Randy Dunlap @ 2008-04-23 7:59 ` K. Prasad 0 siblings, 0 replies; 14+ messages in thread From: K. Prasad @ 2008-04-23 7:59 UTC (permalink / raw) To: Randy Dunlap Cc: prasad, David Wilder, linux-kernel, mathieu.desnoyers, hunt, michaele, dave On Tue, Apr 22, 2008 at 07:53:33AM -0700, Randy Dunlap wrote: > K. Prasad wrote: > > >This patch introduces two new interfaces called debugfs_printk and > >debugfs_dump which can be used to print to the debugfs mount directly. > >It uses the 'trace' infrastructure underneath and is a patch over it. > >A sample file is also created to demonstrate its ease of use. > > > >Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> > >--- > > Documentation/trace.txt | 21 ++++ > > include/linux/trace.h | 55 +++++++++++ > > lib/trace.c | 193 > > +++++++++++++++++++++++++++++++++++++++-- > > samples/trace/Makefile | 2 > > samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ > > 5 files changed, 362 insertions(+), 6 deletions(-) > > >+ > >+/** > >+ * debugfs_printk - Output binary into debugfs mount 'directly' using > >'trace' > > Oops. This is the debugfs_dump() function. Missed again. Sending the patch again with that minor change. > > Otherwise it looks good. Thanks. > > >+ * @dpk: Structure containing info such as parent_dir and directory > >+ * @output: Data that needs to be output > >+ * @output_len: Length of the output data > >+ */ > >+int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > >+ const int output_len) > >+{ > > > -- > ~Randy This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- Documentation/trace.txt | 21 ++++ include/linux/trace.h | 55 +++++++++++ lib/trace.c | 193 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 97 ++++++++++++++++++++ 5 files changed, 362 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,31 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; + unsigned long flags; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +94,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +115,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +132,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,7 +29,9 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); +static DEFINE_SPINLOCK(trace_lock); static int state_open(struct inode *inode, struct file *filp) { @@ -99,9 +101,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +154,14 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,16 +170,49 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; +} + +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; } +EXPORT_SYMBOL_GPL(trace_exists); static int dropped_open(struct inode *inode, struct file *filp) { @@ -561,3 +609,138 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace directories under a parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data *dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch(dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if(!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if(!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + if(!dpk->flags) + dpk->flags = TRACE_FLIGHT_CHANNEL; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, dpk->flags); + printk(KERN_INFO "Trace interface %s setup through " + "debugfs_printk\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state != TRACE_RUNNING) { + trace_start(ti); + } + } + return ti; +} + +/** + * debugfs_printk - Output a string to debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @format: String containing format string specifiers + * @ap: List of arguments + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + unsigned long flags; + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + /* Take an RCU Lock over the trace_info state */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + ret = trace_printf(ti, format, ap); + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/** + * debugfs_dump - Output binary into debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @output: Data that needs to be output + * @output_len: Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + record = relay_reserve(ti->rchan, output_len); + if (record) + memcpy(record, output, output_len); + else + return -ENOMEM; + rcu_read_unlock(); + + return 0; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,97 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2007 IBM Inc. + * + * David Wilder <dwilder@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if(!dpk) ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if(ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt =================================================================== --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt @@ -150,6 +150,27 @@ The steps a kernel data provider takes t 5) Destroy the trace channel and underlying relay channel - trace_cleanup(). +Alternatively the user may choose to make use of two new interfaces -- +debugfs_printk() and debugfs_dump() -- to setup trace interface and +trace_cleanup_all() to tear-down the same. + +Steps to use: +1) Create and populate an instance of debugfs_printk_data structure. The fields + parent_dir and dir are mandatory. The fields buf_size, sub_buf_size and flags + are optional and will take default values if not populated. The field + 'exists' is for the trace infrastructure to use. +2) Default values for buf_size, sub_buf_size and flags are 4096, 40 and + TRACE_FLIGHT_CHANNEL respectively. +3) Use debugfs_dump() to output binary data which may be acted upon by a + high-level program (say dumping a structure). debugfs_printk() can be used + for string output. Pass a pointer to the instance of debugfs_printk_data + structure to these functions along with other parameters. The output from + these functions can be found at + <debugfs_mount>/<parent_dir>/<dir>/trace<0..n>. +4) trace_cleanup_all() for a given parent directory will cleanup and remove all + trace directories created under the specified directory. +5) Sample code for the same can be found in samples/trace/fork_new_trace.c + Kernel Configuration -------------------- To use trace, configure your kernel with CONFIG_TRACE=y. Trace depends on ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-21 12:43 ` K. Prasad 2008-04-21 17:14 ` Randy Dunlap @ 2008-04-24 21:23 ` David Wilder 2008-04-25 7:42 ` K. Prasad 1 sibling, 1 reply; 14+ messages in thread From: David Wilder @ 2008-04-24 21:23 UTC (permalink / raw) To: prasad; +Cc: linux-kernel, mathieu.desnoyers, hunt, michaele, dave debugfs_print makes a great improvement to the trace interface. I missing a couple of bugs the first time I reviewed it. Please see my comments in-line. Dave.. > +static inline struct trace_info *init_trace_interface(struct > + debugfs_printk_data *dpk) > +{ > + struct trace_info *ti; > + > + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); > + > + switch(dpk->exists) { > + > + case TRACE_PARENT_DIR_EXISTS: > + case TRACE_PARENT_DIR_ABSENT: > + if(!dpk->buf_size) > + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; > + if(!dpk->sub_buf_size) > + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; > + if(!dpk->flags) > + dpk->flags = TRACE_FLIGHT_CHANNEL; > + ti = trace_setup(dpk->parent_dir, dpk->dir, > + dpk->buf_size, dpk->sub_buf_size, dpk->flags); > + printk(KERN_INFO "Trace interface %s setup through " > + "debugfs_printk\n", > + ti->dir->d_iname); > + if (IS_ERR(ti)) { > + printk(KERN_ERR "Trace interface could not be " > + "initialised\n"); > + return PTR_ERR(ti); > + } > + /* Fall through */ > + case TRACE_DIR_EXISTS: > + if (ti->state != TRACE_RUNNING) { You should start the trace only if the current state is TRACE_SETUP (I think). See my comment in debugfs_print() if (ti->state == TRACE_SETUP) > + trace_start(ti); > + } > + } > + return ti; > +} > + > +/* > + * debugfs_printk - A function to write into the debugfs mount 'directly' > + * using 'trace' infrastructure > + * @dpk - Structure containing info such as parent_dir and directory > + * @format - String containing format string specifiers > + * @ap - List of arguments > + */ > +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) > +{ > + int ret; > + struct trace_info *ti; > + va_list(ap); > + unsigned long flags; > + > + va_start(ap, format); > + > + ti = init_trace_interface(dpk); init_trace_interface() alway sets trace->state to TRACE_RUNNING . The results is that the user is prevented from stopping the trace. You can see this in fork_new_trace. $ cat debug/trace_new_example/do_fork/state running $ echo stop > debug/trace_new_example/do_fork/state $ cat debug/trace_new_example/do_fork/state running > + > + /* Now do the actual printing */ > + /* Take an RCU Lock over the trace_info state */ > + rcu_read_lock(); > + /* Take a spinlock for the global buffer used by relay */ > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > + spin_lock_irqsave(&trace_lock, flags); > + ret = trace_printf(ti, format, ap); > + if (dpk->flags & TRACE_GLOBAL_CHANNEL) > + spin_unlock_irqrestore(&trace_lock, flags); > + rcu_read_unlock(); > + > + va_end(ap); > + return ret; > +} > +EXPORT_SYMBOL(debugfs_printk); > + > +/* > + * debugfs_printk - A function to write into the debugfs mount 'directly' > + * using 'trace' infrastructure > + * @dpk - Structure containing info such as parent_dir and directory > + * @output - Data that needs to be output > + * @output_len - Length of the output data > + */ > +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > + const int output_len) > +{ > + struct trace_info *ti; > + char *record; > + > + ti = init_trace_interface(dpk); Same issue as debugfs_printf, You should also check for trace_running as you did for trace_printf. > + > + /* Now do the actual printing */ > + rcu_read_lock(); > + record = relay_reserve(ti->rchan, output_len); > + if (record) > + memcpy(record, output, output_len); > + else > + return -ENOMEM; > + rcu_read_unlock(); > + > + return 0; > +} > +EXPORT_SYMBOL(debugfs_dump); ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-24 21:23 ` David Wilder @ 2008-04-25 7:42 ` K. Prasad 2008-04-25 8:19 ` K. Prasad 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-25 7:42 UTC (permalink / raw) To: David Wilder Cc: prasad, linux-kernel, mathieu.desnoyers, hunt, michaele, dave On Thu, Apr 24, 2008 at 02:23:16PM -0700, David Wilder wrote: > > debugfs_print makes a great improvement to the trace interface. I Thanks. > missing a couple of bugs the first time I reviewed it. Please see my > comments in-line. > > Dave.. > > > >+static inline struct trace_info *init_trace_interface(struct > >+ debugfs_printk_data *dpk) > >+{ > >+ struct trace_info *ti; > >+ > >+ dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); > >+ > >+ switch(dpk->exists) { > >+ > >+ case TRACE_PARENT_DIR_EXISTS: > >+ case TRACE_PARENT_DIR_ABSENT: > >+ if(!dpk->buf_size) > >+ dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; > >+ if(!dpk->sub_buf_size) > >+ dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; > >+ if(!dpk->flags) > >+ dpk->flags = TRACE_FLIGHT_CHANNEL; > >+ ti = trace_setup(dpk->parent_dir, dpk->dir, > >+ dpk->buf_size, dpk->sub_buf_size, dpk->flags); > >+ printk(KERN_INFO "Trace interface %s setup through " > >+ > >"debugfs_printk\n", > >+ ti->dir->d_iname); > >+ if (IS_ERR(ti)) { > >+ printk(KERN_ERR "Trace interface could not be " > >+ "initialised\n"); > >+ return PTR_ERR(ti); > >+ } > >+ /* Fall through */ > >+ case TRACE_DIR_EXISTS: > >+ if (ti->state != TRACE_RUNNING) { > > You should start the trace only if the current state is TRACE_SETUP (I > think). See my comment in debugfs_print() > > > if (ti->state == TRACE_SETUP) > >+ trace_start(ti); > >+ } > >+ } > >+ return ti; > >+} > >+ > >+/* > >+ * debugfs_printk - A function to write into the debugfs mount 'directly' > >+ * using 'trace' infrastructure > >+ * @dpk - Structure containing info such as parent_dir and directory > >+ * @format - String containing format string specifiers > >+ * @ap - List of arguments > >+ */ > >+int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) > >+{ > >+ int ret; > >+ struct trace_info *ti; > >+ va_list(ap); > >+ unsigned long flags; > >+ > >+ va_start(ap, format); > >+ > >+ ti = init_trace_interface(dpk); > > init_trace_interface() alway sets trace->state to TRACE_RUNNING . The > results is that the user is prevented from stopping the trace. You can > see this in fork_new_trace. This is actually an intentional design to guarantee that debugfs_* would output the data overriding the control (the state was retained to enable interoperability with other users of trace over the same parent_dir/dir combination). On further thought, it does make sense to enable the user to control the output. I will include your suggested changes. > > $ cat debug/trace_new_example/do_fork/state > running > $ echo stop > debug/trace_new_example/do_fork/state > $ cat debug/trace_new_example/do_fork/state > running > > >+ > >+ /* Now do the actual printing */ > >+ /* Take an RCU Lock over the trace_info state */ > >+ rcu_read_lock(); > >+ /* Take a spinlock for the global buffer used by relay */ > >+ if (dpk->flags & TRACE_GLOBAL_CHANNEL) > >+ spin_lock_irqsave(&trace_lock, flags); > >+ ret = trace_printf(ti, format, ap); > >+ if (dpk->flags & TRACE_GLOBAL_CHANNEL) > >+ spin_unlock_irqrestore(&trace_lock, flags); > >+ rcu_read_unlock(); > >+ > >+ va_end(ap); > >+ return ret; > >+} > >+EXPORT_SYMBOL(debugfs_printk); > >+ > >+/* > >+ * debugfs_printk - A function to write into the debugfs mount 'directly' > >+ * using 'trace' infrastructure > >+ * @dpk - Structure containing info such as parent_dir and directory > >+ * @output - Data that needs to be output > >+ * @output_len - Length of the output data > >+ */ > >+int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, > >+ const int output_len) > >+{ > >+ struct trace_info *ti; > >+ char *record; > >+ > >+ ti = init_trace_interface(dpk); > > Same issue as debugfs_printf, > > You should also check for trace_running as you did for trace_printf. Thanks for pointing this out. I missed it. I'm also enclosing the memcpy with a spinlock if the TRACE_GLOBAL_CHANNEL flag is set. Please find the new patch below. > > > >+ > >+ /* Now do the actual printing */ > >+ rcu_read_lock(); > >+ record = relay_reserve(ti->rchan, output_len); > >+ if (record) > >+ memcpy(record, output, output_len); > >+ else > >+ return -ENOMEM; > >+ rcu_read_unlock(); > >+ > >+ return 0; > >+} > >+EXPORT_SYMBOL(debugfs_dump); This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- Documentation/trace.txt | 21 ++++ include/linux/trace.h | 55 +++++++++++ lib/trace.c | 202 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 97 +++++++++++++++++++ 5 files changed, 371 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,31 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; + unsigned long flags; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +94,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +115,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +132,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,7 +29,9 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); +static DEFINE_SPINLOCK(trace_lock); static int state_open(struct inode *inode, struct file *filp) { @@ -99,9 +101,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +154,14 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,16 +170,49 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; +} + +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; } +EXPORT_SYMBOL_GPL(trace_exists); static int dropped_open(struct inode *inode, struct file *filp) { @@ -561,3 +609,147 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace directories under a parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data *dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch(dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if(!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if(!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + if(!dpk->flags) + dpk->flags = TRACE_FLIGHT_CHANNEL; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, dpk->flags); + printk(KERN_INFO "Trace interface %s setup through " + "debugfs_printk\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state != TRACE_RUNNING) { + trace_start(ti); + } + } + return ti; +} + +/** + * debugfs_printk - Output a string to debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @format: String containing format string specifiers + * @ap: List of arguments + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + unsigned long flags; + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + /* Take an RCU Lock over the trace_info state */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + ret = trace_printf(ti, format, ap); + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/** + * debugfs_dump - Output binary into debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @output: Data that needs to be output + * @output_len: Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + unsigned long flags; + int ret = 0; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + record = relay_reserve(ti->rchan, output_len); + + if (record && trace_running(trace)) + memcpy(record, output, output_len); + else + ret = -ENOMEM; + + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,97 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2007 IBM Inc. + * + * David Wilder <dwilder@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if(!dpk) ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if(ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt =================================================================== --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt @@ -150,6 +150,27 @@ The steps a kernel data provider takes t 5) Destroy the trace channel and underlying relay channel - trace_cleanup(). +Alternatively the user may choose to make use of two new interfaces -- +debugfs_printk() and debugfs_dump() -- to setup trace interface and +trace_cleanup_all() to tear-down the same. + +Steps to use: +1) Create and populate an instance of debugfs_printk_data structure. The fields + parent_dir and dir are mandatory. The fields buf_size, sub_buf_size and flags + are optional and will take default values if not populated. The field + 'exists' is for the trace infrastructure to use. +2) Default values for buf_size, sub_buf_size and flags are 4096, 40 and + TRACE_FLIGHT_CHANNEL respectively. +3) Use debugfs_dump() to output binary data which may be acted upon by a + high-level program (say dumping a structure). debugfs_printk() can be used + for string output. Pass a pointer to the instance of debugfs_printk_data + structure to these functions along with other parameters. The output from + these functions can be found at + <debugfs_mount>/<parent_dir>/<dir>/trace<0..n>. +4) trace_cleanup_all() for a given parent directory will cleanup and remove all + trace directories created under the specified directory. +5) Sample code for the same can be found in samples/trace/fork_new_trace.c + Kernel Configuration -------------------- To use trace, configure your kernel with CONFIG_TRACE=y. Trace depends on ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-25 7:42 ` K. Prasad @ 2008-04-25 8:19 ` K. Prasad 2008-04-28 0:50 ` Michael Ellerman 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-25 8:19 UTC (permalink / raw) To: dwilder; +Cc: linux-kernel, mathieu.desnoyers, hunt, michaele, dave, prasad On Fri, Apr 25, 2008 at 01:12:00PM +0530, K. Prasad wrote: > Please find the new patch below. > > Let the email slip through a little early. Please find the revised patch below. Thanks, K.Prasad This patch introduces two new interfaces called debugfs_printk and debugfs_dump which can be used to print to the debugfs mount directly. It uses the 'trace' infrastructure underneath and is a patch over it. A sample file is also created to demonstrate its ease of use. Signed-off-by: K.Prasad <prasad@linux.vnet.ibm.com> --- Documentation/trace.txt | 21 ++++ include/linux/trace.h | 55 +++++++++++ lib/trace.c | 202 +++++++++++++++++++++++++++++++++++++++-- samples/trace/Makefile | 2 samples/trace/fork_new_trace.c | 97 +++++++++++++++++++ 5 files changed, 371 insertions(+), 6 deletions(-) Index: linux-2.6.25-rc8-mm1/include/linux/trace.h =================================================================== --- linux-2.6.25-rc8-mm1.orig/include/linux/trace.h +++ linux-2.6.25-rc8-mm1/include/linux/trace.h @@ -39,10 +39,31 @@ enum trace_state { TRACE_STOPPED, }; +enum trace_dir_state { + TRACE_PARENT_DIR_ABSENT, + TRACE_PARENT_DIR_EXISTS, + TRACE_DIR_EXISTS +}; + #define TRACE_ROOT_NAME_SIZE 64 /* Max root dir identifier */ #define TRACE_NAME_SIZE 64 /* Max trace identifier */ /* + * Buffers for use by debugfs_printk + */ +#define DEFAULT_TRACE_BUF_SIZE 4096 +#define DEFAULT_TRACE_SUB_BUF_NR 40 + +struct debugfs_printk_data { + char *parent_dir; + char *dir; + int exists; + int buf_size; + int sub_buf_size; + unsigned long flags; +}; + +/* * Global root user information */ struct trace_root { @@ -73,6 +94,17 @@ struct trace_info { unsigned int buf_nr; }; +/* + * Information about every trace directory + */ +struct trace_dir { + struct list_head trace_dir_list; + char trace_dir_name[TRACE_NAME_SIZE]; + struct dentry *trace_root; + struct dentry *trace_dir; + struct trace_info *ti; +}; + #ifdef CONFIG_TRACE static inline int trace_running(struct trace_info *trace) { @@ -83,6 +115,12 @@ struct trace_info *trace_setup(const cha int trace_start(struct trace_info *trace); int trace_stop(struct trace_info *trace); void trace_cleanup(struct trace_info *trace); +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti); +void trace_cleanup_all(const char *parent_dir); +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...); +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len); #else static inline struct trace_info *trace_setup(const char *root, const char *name, u32 buf_size, @@ -94,6 +132,23 @@ static inline int trace_start(struct tra static inline int trace_stop(struct trace_info *trace) { return -EINVAL; } static inline int trace_running(struct trace_info *trace) { return 0; } static inline void trace_cleanup(struct trace_info *trace) {} +static inline int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + return -EINVAL; +} +static inline void trace_cleanup_all(const char *parent_dir) {} +static inline int debugfs_printk(struct debugfs_printk_data *dpk, char *format, + ...) +{ + return -EINVAL; +} +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + return -EINVAL; +} + #endif #endif Index: linux-2.6.25-rc8-mm1/lib/trace.c =================================================================== --- linux-2.6.25-rc8-mm1.orig/lib/trace.c +++ linux-2.6.25-rc8-mm1/lib/trace.c @@ -29,7 +29,9 @@ #include <linux/trace.h> static LIST_HEAD(trace_roots); +static LIST_HEAD(trace_dirs); static DEFINE_MUTEX(trace_mutex); +static DEFINE_SPINLOCK(trace_lock); static int state_open(struct inode *inode, struct file *filp) { @@ -99,9 +101,19 @@ static void remove_root(struct trace_inf static void remove_tree(struct trace_info *trace) { + struct list_head *pos, *temp; + struct trace_dir *dr = NULL; + mutex_lock(&trace_mutex); debugfs_remove(trace->dir); + list_for_each_safe(pos, temp, &trace_dirs) { + dr = list_entry(pos, struct trace_dir, trace_dir_list); + if (dr->ti == trace) { + list_del(pos); + kfree(dr); + } + } if (trace->root) { if (--trace->root->users == 0) remove_root(trace); @@ -142,11 +154,14 @@ static struct trace_root *lookup_root(co static struct dentry *create_tree(struct trace_info *trace, const char *root, const char *name) { - struct dentry *dir = NULL; + struct trace_dir *temp; if (root == NULL || name == NULL) return ERR_PTR(-EINVAL); + temp = kzalloc(sizeof(struct trace_dir), GFP_KERNEL); + strncpy(temp->trace_dir_name, name, strlen(name)); + mutex_lock(&trace_mutex); trace->root = lookup_root(root); @@ -155,17 +170,50 @@ static struct dentry *create_tree(struct goto err; } - dir = debugfs_create_dir(name, trace->root->root); - if (IS_ERR(dir)) + temp->trace_root = trace->root->root; + temp->trace_dir = debugfs_create_dir(name, trace->root->root); + + if (IS_ERR(temp->trace_dir)) remove_root(trace); - else + else { trace->root->users++; + temp->ti = trace; + list_add_tail(&temp->trace_dir_list, &trace_dirs); + } err: mutex_unlock(&trace_mutex); - return dir; + return temp->trace_dir; } +int trace_exists(const char *parent_dir, const char *dir, + struct trace_info **ti) +{ + struct list_head *pos; + struct trace_root *r; + struct trace_dir *temp; + int ret = TRACE_PARENT_DIR_ABSENT; + + list_for_each(pos, &trace_roots) { + r = list_entry(pos, struct trace_root, list); + if (!strcmp(parent_dir, r->name)) + goto search_dir; + } + return ret; + + search_dir: + list_for_each(pos, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + + if (!strcmp(dir, temp->trace_dir_name)) { + *ti = temp->ti; + return TRACE_DIR_EXISTS; + } + } + return TRACE_PARENT_DIR_EXISTS; +} +EXPORT_SYMBOL_GPL(trace_exists); + static int dropped_open(struct inode *inode, struct file *filp) { filp->private_data = inode->i_private; @@ -561,3 +609,147 @@ void trace_cleanup(struct trace_info *tr kfree(trace); } EXPORT_SYMBOL_GPL(trace_cleanup); + +/** + * trace_cleanup_all - Removes all trace directories under a parent_dir + * @parent_dir: Name of the parent directory + */ +void trace_cleanup_all(const char *parent_dir) +{ + struct list_head *pos, *pos_temp; + struct trace_dir *temp; + + list_for_each_safe(pos, pos_temp, &trace_dirs) { + temp = list_entry(pos, struct trace_dir, trace_dir_list); + if (!strcmp(parent_dir, temp->trace_root->d_iname)) + trace_cleanup(temp->ti); + } +} +EXPORT_SYMBOL_GPL(trace_cleanup_all); + +/* + * Send formatted trace data to trace channel. + */ +static int trace_printf(struct trace_info *trace, const char *format, + va_list ap) +{ + va_list aq; + char *record; + int len; + int ret = 0; + + if (trace_running(trace)) { + va_copy(aq, ap); + len = vsnprintf(NULL, 0, format, aq); + va_end(aq); + record = relay_reserve(trace->rchan, ++len); + if (record) + ret = vsnprintf(record, len, format, ap); + } + return ret; +} + +static inline struct trace_info *init_trace_interface(struct + debugfs_printk_data *dpk) +{ + struct trace_info *ti; + + dpk->exists = trace_exists(dpk->parent_dir, dpk->dir, &ti); + + switch(dpk->exists) { + + case TRACE_PARENT_DIR_EXISTS: + case TRACE_PARENT_DIR_ABSENT: + if(!dpk->buf_size) + dpk->buf_size = DEFAULT_TRACE_BUF_SIZE; + if(!dpk->sub_buf_size) + dpk->sub_buf_size = DEFAULT_TRACE_SUB_BUF_NR; + if(!dpk->flags) + dpk->flags = TRACE_FLIGHT_CHANNEL; + ti = trace_setup(dpk->parent_dir, dpk->dir, + dpk->buf_size, dpk->sub_buf_size, dpk->flags); + printk(KERN_INFO "Trace interface %s setup through " + "debugfs_printk\n", + ti->dir->d_iname); + if (IS_ERR(ti)) { + printk(KERN_ERR "Trace interface could not be " + "initialised\n"); + return PTR_ERR(ti); + } + /* Fall through */ + case TRACE_DIR_EXISTS: + if (ti->state == TRACE_SETUP) { + trace_start(ti); + } + } + return ti; +} + +/** + * debugfs_printk - Output a string to debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @format: String containing format string specifiers + * @ap: List of arguments + */ +int debugfs_printk(struct debugfs_printk_data *dpk, char *format, ...) +{ + int ret; + struct trace_info *ti; + va_list(ap); + unsigned long flags; + + va_start(ap, format); + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + /* Take an RCU Lock over the trace_info state */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + ret = trace_printf(ti, format, ap); + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + va_end(ap); + return ret; +} +EXPORT_SYMBOL(debugfs_printk); + +/** + * debugfs_dump - Output binary into debugfs mount 'directly' using 'trace' + * @dpk: Structure containing info such as parent_dir and directory + * @output: Data that needs to be output + * @output_len: Length of the output data + */ +int debugfs_dump(struct debugfs_printk_data *dpk, const void *output, + const int output_len) +{ + struct trace_info *ti; + char *record; + unsigned long flags; + int ret = 0; + + ti = init_trace_interface(dpk); + + /* Now do the actual printing */ + rcu_read_lock(); + /* Take a spinlock for the global buffer used by relay */ + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_lock_irqsave(&trace_lock, flags); + record = relay_reserve(ti->rchan, output_len); + + if (record && trace_running(trace)) + memcpy(record, output, output_len); + else + record ? ret = -EPERM : ret = -ENOMEM; + + if (dpk->flags & TRACE_GLOBAL_CHANNEL) + spin_unlock_irqrestore(&trace_lock, flags); + rcu_read_unlock(); + + return ret; +} +EXPORT_SYMBOL(debugfs_dump); Index: linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c =================================================================== --- /dev/null +++ linux-2.6.25-rc8-mm1/samples/trace/fork_new_trace.c @@ -0,0 +1,97 @@ +/* + * An example of using trace in a kprobes module + * + * Copyright (C) 2007 IBM Inc. + * + * David Wilder <dwilder@us.ibm.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * ------- + * This module creates a trace channel and places a kprobe + * on the function do_fork(). The value of current->pid is written to + * the trace channel each time the kprobe is hit.. + * + * How to run the example: + * $ mount -t debugfs /debug + * $ insmod fork_trace.ko + * + * To view the data produced by the module: + * $ cat /debug/trace_example/do_fork/trace0 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/kprobes.h> +#include <linux/trace.h> + +#define SAMPLE_PARENT_DIR "trace_new_example" +#define PROBE_POINT "do_fork" + +static struct kprobe kp; +static struct debugfs_printk_data *dpk; + +static int handler_pre(struct kprobe *p, struct pt_regs *regs) +{ + debugfs_printk(dpk, "%d\n", current->pid); + return 0; +} + +int init_module(void) +{ + int ret = 0; + int len_parent_dir, len_dir; + + /* setup the kprobe */ + kp.pre_handler = handler_pre; + kp.post_handler = NULL; + kp.fault_handler = NULL; + kp.symbol_name = PROBE_POINT; + ret = register_kprobe(&kp); + if (ret) { + printk(KERN_ERR "fork_trace: register_kprobe failed\n"); + return ret; + } + + len_parent_dir = strlen(SAMPLE_PARENT_DIR) + 1; + /* Initialising len_dir to the larger of the two dir names */ + len_dir = strlen("kprobe_struct") + 1; + + dpk = kzalloc(sizeof(*dpk), GFP_KERNEL); + if(!dpk) ret = 1; + + dpk->parent_dir = SAMPLE_PARENT_DIR; + + /* Let's do a binary dump of struct kprobe using debugfs_dump */ + dpk->dir = "kprobes_struct"; + debugfs_dump(dpk, &kp, sizeof(kp)); + + /* Now change the directory to collect fork pid data */ + dpk->dir = PROBE_POINT; + + if(ret) + printk(KERN_ERR "Unable to find required free memory. " + "Trace new sample module loading aborted"); + return ret; +} + +void cleanup_module(void) +{ + unregister_kprobe(&kp); + + /* Just a single cleanup call passing the parent dir string */ + trace_cleanup_all(SAMPLE_PARENT_DIR); +} +MODULE_LICENSE("GPL"); Index: linux-2.6.25-rc8-mm1/samples/trace/Makefile =================================================================== --- linux-2.6.25-rc8-mm1.orig/samples/trace/Makefile +++ linux-2.6.25-rc8-mm1/samples/trace/Makefile @@ -1,4 +1,4 @@ # builds the trace example kernel modules; # then to use (as root): insmod <fork_trace.ko> -obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o +obj-$(CONFIG_SAMPLE_TRACE) := fork_trace.o fork_new_trace.o Index: linux-2.6.25-rc8-mm1/Documentation/trace.txt =================================================================== --- linux-2.6.25-rc8-mm1.orig/Documentation/trace.txt +++ linux-2.6.25-rc8-mm1/Documentation/trace.txt @@ -150,6 +150,27 @@ The steps a kernel data provider takes t 5) Destroy the trace channel and underlying relay channel - trace_cleanup(). +Alternatively the user may choose to make use of two new interfaces -- +debugfs_printk() and debugfs_dump() -- to setup trace interface and +trace_cleanup_all() to tear-down the same. + +Steps to use: +1) Create and populate an instance of debugfs_printk_data structure. The fields + parent_dir and dir are mandatory. The fields buf_size, sub_buf_size and flags + are optional and will take default values if not populated. The field + 'exists' is for the trace infrastructure to use. +2) Default values for buf_size, sub_buf_size and flags are 4096, 40 and + TRACE_FLIGHT_CHANNEL respectively. +3) Use debugfs_dump() to output binary data which may be acted upon by a + high-level program (say dumping a structure). debugfs_printk() can be used + for string output. Pass a pointer to the instance of debugfs_printk_data + structure to these functions along with other parameters. The output from + these functions can be found at + <debugfs_mount>/<parent_dir>/<dir>/trace<0..n>. +4) trace_cleanup_all() for a given parent directory will cleanup and remove all + trace directories created under the specified directory. +5) Sample code for the same can be found in samples/trace/fork_new_trace.c + Kernel Configuration -------------------- To use trace, configure your kernel with CONFIG_TRACE=y. Trace depends on ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-25 8:19 ` K. Prasad @ 2008-04-28 0:50 ` Michael Ellerman 2008-04-28 4:48 ` K. Prasad 0 siblings, 1 reply; 14+ messages in thread From: Michael Ellerman @ 2008-04-28 0:50 UTC (permalink / raw) To: prasad; +Cc: dwilder, linux-kernel, mathieu.desnoyers, hunt, dave [-- Attachment #1: Type: text/plain, Size: 1265 bytes --] On Fri, 2008-04-25 at 13:49 +0530, K. Prasad wrote: > On Fri, Apr 25, 2008 at 01:12:00PM +0530, K. Prasad wrote: > > Please find the new patch below. > > > > Let the email slip through a little early. Please find the revised > patch below. > > Thanks, > K.Prasad > > This patch introduces two new interfaces called debugfs_printk and > debugfs_dump which can be used to print to the debugfs mount directly. > It uses the 'trace' infrastructure underneath and is a patch over it. > A sample file is also created to demonstrate its ease of use. I still think debugfs_printk() is not the right name, as it is not part of the existing family of debugfs_* routines. > Documentation/trace.txt | 21 ++++ > include/linux/trace.h | 55 +++++++++++ > lib/trace.c | 202 +++++++++++++++++++++++++++++++++++++++-- > samples/trace/Makefile | 2 > samples/trace/fork_new_trace.c | 97 +++++++++++++++++++ And it's not in debugfs.h cheers -- Michael Ellerman OzLabs, IBM Australia Development Lab wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-28 0:50 ` Michael Ellerman @ 2008-04-28 4:48 ` K. Prasad 2008-04-28 4:54 ` Michael Ellerman 0 siblings, 1 reply; 14+ messages in thread From: K. Prasad @ 2008-04-28 4:48 UTC (permalink / raw) To: Michael Ellerman Cc: prasad, dwilder, linux-kernel, mathieu.desnoyers, hunt, dave On Mon, Apr 28, 2008 at 10:50:51AM +1000, Michael Ellerman wrote: > On Fri, 2008-04-25 at 13:49 +0530, K. Prasad wrote: > > On Fri, Apr 25, 2008 at 01:12:00PM +0530, K. Prasad wrote: > > > Please find the new patch below. > > > > > > Let the email slip through a little early. Please find the revised > > patch below. > > > > Thanks, > > K.Prasad > > > > This patch introduces two new interfaces called debugfs_printk and > > debugfs_dump which can be used to print to the debugfs mount directly. > > It uses the 'trace' infrastructure underneath and is a patch over it. > > A sample file is also created to demonstrate its ease of use. > > I still think debugfs_printk() is not the right name, as it is not part > of the existing family of debugfs_* routines. Whether to call it trace_printk() and trace_dump() is a suggestion I would like to ask David Wilder (and others). Let me know if you think there are better names. Thanks, K.Prasad ^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [RFC Patch 1/1] debugfs_printk and debugfs_dump interface 2008-04-28 4:48 ` K. Prasad @ 2008-04-28 4:54 ` Michael Ellerman 0 siblings, 0 replies; 14+ messages in thread From: Michael Ellerman @ 2008-04-28 4:54 UTC (permalink / raw) To: prasad; +Cc: dwilder, linux-kernel, mathieu.desnoyers, hunt, dave [-- Attachment #1: Type: text/plain, Size: 1467 bytes --] On Mon, 2008-04-28 at 10:18 +0530, K. Prasad wrote: > On Mon, Apr 28, 2008 at 10:50:51AM +1000, Michael Ellerman wrote: > > On Fri, 2008-04-25 at 13:49 +0530, K. Prasad wrote: > > > On Fri, Apr 25, 2008 at 01:12:00PM +0530, K. Prasad wrote: > > > > Please find the new patch below. > > > > > > > > Let the email slip through a little early. Please find the revised > > > patch below. > > > > > > Thanks, > > > K.Prasad > > > > > > This patch introduces two new interfaces called debugfs_printk and > > > debugfs_dump which can be used to print to the debugfs mount directly. > > > It uses the 'trace' infrastructure underneath and is a patch over it. > > > A sample file is also created to demonstrate its ease of use. > > > > I still think debugfs_printk() is not the right name, as it is not part > > of the existing family of debugfs_* routines. > Whether to call it trace_printk() and trace_dump() is a suggestion I > would like to ask David Wilder (and others). Let me know if you think > there are better names. That would be my pick, given that it's using the trace infrastructure and it's defined in trace.h, implemented in trace.c, and documented in trace.txt :) cheers -- Michael Ellerman OzLabs, IBM Australia Development Lab wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 14+ messages in thread
end of thread, other threads:[~2008-04-28 4:54 UTC | newest] Thread overview: 14+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-04-15 11:14 [RFC Patch 0/1] Enhancements to 'trace' infrastructure K. Prasad 2008-04-15 11:26 ` [RFC Patch 1/1] debugfs_printk and debugfs_dump interface K. Prasad 2008-04-16 21:25 ` David Wilder 2008-04-21 12:43 ` K. Prasad 2008-04-21 17:14 ` Randy Dunlap 2008-04-22 5:22 ` K. Prasad 2008-04-22 14:53 ` Randy Dunlap 2008-04-23 7:59 ` K. Prasad 2008-04-24 21:23 ` David Wilder 2008-04-25 7:42 ` K. Prasad 2008-04-25 8:19 ` K. Prasad 2008-04-28 0:50 ` Michael Ellerman 2008-04-28 4:48 ` K. Prasad 2008-04-28 4:54 ` Michael Ellerman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox