From mboxrd@z Thu Jan 1 00:00:00 1970 From: zhaolei@cn.fujitsu.com (Zhaolei) Date: Mon, 27 Oct 2008 11:47:12 +0800 Subject: [ltt-dev] [PATCH] Separate ltt_trace_create() into ltt_trace_create() and ltt_trace_alloc() In-Reply-To: <20081020031634.GA14209@Krystal> References: <48F733E6.9010007@cn.fujitsu.com> <48F80CDD.2070205@cn.fujitsu.com> <20081017042045.GB5067@Krystal> <20081017161429.GA5696@Krystal> <20081020031634.GA14209@Krystal> Message-ID: <490539C0.6040304@cn.fujitsu.com> This is step1 of: "switch marker list and marker activation (currently in /proc/ltt) to debugfs" > >> Are you means we can control each channel's (interrupt, process, ...) > >> subbuf in future version? > >> (I think current version can only control low, med and high) > >> If this is true, maybe we need modify ltt_trace_create() before impl > >> ltt_control. > >> > > Yes, this is the goal. > So, IMHO, we can do it in following steps: > > Step1: modify ltt_trace_create(), .etc, separate ltt_trace_create() into > ltt_trace_setup(), ltt_set_channelsize(), ltt_set_channelnum(), > ltt_trace_alloc(). But still use old netlink_based ltt_control to make > it simple. > Although we modify ltt_set_channelsize() to support setting each channel's > buffer, we make ltt_control.ko using old UI(only able to set low, med and > high). So we don't need to modify other program such as user-mode lttctl. > Yes. Just make sure a "destroy" deals correctly with a trace that is "setup" but not "allocated" yet. > Step2: Write a new module named ltt-channel-control. > ( I think name of ltt-channel-control will be better than ltt-control, > because we already have a module named ltt-marker-control. ) > ltt-channel-control is designed on debugfs, as we discussed. > We can test it by echo XX > /mnt/debugfs/ltt/... > Yes, that would be perfect. > Step3: modify user-mode programs to support ltt-channel-control. > We also need to modify lttctl's command arguments, to support setup each > channel's buffer. (Are we take out -Z, -X, -V, -B, -z, -x in lttctl?) > I haven't read source of lttv, it is necessary to modify? > Maybe we could replace lttctl by simple shell scripts ? Yes, small modification of lttv would be required. There is a GUI module which executes lttctl to start/stop tracing. It would have to be modified so it uses the debugfs files instead. Signed-off-by: Zhao Lei --- include/linux/ltt-core.h | 3 +- include/linux/ltt-tracer.h | 40 ++-- ltt/ltt-core.c | 1 + ltt/ltt-tracer.c | 560 ++++++++++++++++++++++++++++++++++---------- 4 files changed, 464 insertions(+), 140 deletions(-) diff --git a/include/linux/ltt-core.h b/include/linux/ltt-core.h index 1681e82..db890d8 100644 --- a/include/linux/ltt-core.h +++ b/include/linux/ltt-core.h @@ -17,7 +17,8 @@ * list. */ struct ltt_traces { - struct list_head head; /* Traces list */ + struct list_head prealloc_head; /* Pre-allocated traces list */ + struct list_head head; /* Allocated Traces list */ unsigned int num_active_traces; /* Number of active traces */ } ____cacheline_aligned; diff --git a/include/linux/ltt-tracer.h b/include/linux/ltt-tracer.h index d46bc88..042f518 100644 --- a/include/linux/ltt-tracer.h +++ b/include/linux/ltt-tracer.h @@ -197,6 +197,23 @@ struct ltt_transport { struct ltt_trace_ops ops; }; +/* + * First and last channels in ltt_trace_struct. + */ +#define ltt_channel_index_size() sizeof(struct ltt_channel_struct *) +#define ltt_channel_index_begin() GET_CHANNEL_INDEX(cpu) +#define ltt_channel_index_end() \ + (GET_CHANNEL_INDEX(metadata) + ltt_channel_index_size()) + +enum ltt_channels { + LTT_CHANNEL_CPU, + LTT_CHANNEL_PROCESSES, + LTT_CHANNEL_INTERRUPTS, + LTT_CHANNEL_NETWORK, + LTT_CHANNEL_MODULES, + LTT_CHANNEL_METADATA, + NR_LTT_CHANNELS, +}; enum trace_mode { LTT_TRACE_NORMAL, LTT_TRACE_FLIGHT, LTT_TRACE_HYBRID }; @@ -218,6 +235,12 @@ struct ltt_trace_struct { struct ltt_channel_struct *modules; struct ltt_channel_struct *metadata; } channel; + struct { + struct { + unsigned subbuf_size; + unsigned subbuf_cnt; + } channels[NR_LTT_CHANNELS]; + } setting; u32 freq_scale; u64 start_freq; u64 start_tsc; @@ -236,23 +259,6 @@ struct ltt_trace_struct { char trace_name[NAME_MAX]; } ____cacheline_aligned; -/* - * First and last channels in ltt_trace_struct. - */ -#define ltt_channel_index_size() sizeof(struct ltt_channel_struct *) -#define ltt_channel_index_begin() GET_CHANNEL_INDEX(cpu) -#define ltt_channel_index_end() \ - (GET_CHANNEL_INDEX(metadata) + ltt_channel_index_size()) - -enum ltt_channels { - LTT_CHANNEL_CPU, - LTT_CHANNEL_PROCESSES, - LTT_CHANNEL_INTERRUPTS, - LTT_CHANNEL_NETWORK, - LTT_CHANNEL_MODULES, - LTT_CHANNEL_METADATA, -}; - /* Hardcoded event headers * * event header for a trace with active heartbeat : 27 bits timestamps diff --git a/ltt/ltt-core.c b/ltt/ltt-core.c index abd3d6d..3d7015e 100644 --- a/ltt/ltt-core.c +++ b/ltt/ltt-core.c @@ -12,6 +12,7 @@ /* Traces structures */ struct ltt_traces ltt_traces = { + .prealloc_head = LIST_HEAD_INIT(ltt_traces.prealloc_head), .head = LIST_HEAD_INIT(ltt_traces.head), }; EXPORT_SYMBOL(ltt_traces); diff --git a/ltt/ltt-tracer.c b/ltt/ltt-tracer.c index e4358cf..5eae2b5 100644 --- a/ltt/ltt-tracer.c +++ b/ltt/ltt-tracer.c @@ -268,31 +268,20 @@ static struct ltt_trace_struct *_ltt_trace_find(const char *trace_name) return NULL; } -/* This function must be called with traces semaphore held. */ -static int _ltt_trace_create(const char *trace_name, enum trace_mode mode, - struct ltt_trace_struct *new_trace) +/* _ltt_trace_find_setup : + * find a trace in setup list by given name. + * + * Returns a pointer to the trace structure, NULL if not found. + */ +static struct ltt_trace_struct *_ltt_trace_find_setup(const char *trace_name) { - int err = EPERM; + struct ltt_trace_struct *trace; - if (_ltt_trace_find(trace_name) != NULL) { - printk(KERN_ERR "LTT : Trace %s already exists\n", trace_name); - err = EEXIST; - goto traces_error; - } - if (list_empty(<t_traces.head)) { - probe_id_defrag(); - mod_timer(<t_async_wakeup_timer, - jiffies + LTT_PERCPU_TIMER_INTERVAL); - set_kernel_trace_flag_all_tasks(); - } - list_add_rcu(&new_trace->list, <t_traces.head); - synchronize_sched(); - /* Everything went fine, finish creation */ - return 0; + list_for_each_entry(trace, <t_traces.prealloc_head, list) + if (!strncmp(trace->trace_name, trace_name, NAME_MAX)) + return trace; - /* Error handling */ -traces_error: - return err; + return NULL; } /** @@ -334,170 +323,491 @@ static inline void prepare_chan_size_num(unsigned *subbuf_size, WARN_ON(hweight32(*n_subbufs) != 1); } -static int ltt_trace_create(const char *trace_name, const char *trace_type, - enum trace_mode mode, - unsigned subbuf_size_low, unsigned n_subbufs_low, - unsigned subbuf_size_med, unsigned n_subbufs_med, - unsigned subbuf_size_high, unsigned n_subbufs_high) +static int ltt_trace_setup(const char *trace_name) { int err = 0; - struct ltt_trace_struct *new_trace, *trace; - unsigned long flags; - struct ltt_transport *tran, *transport = NULL; + struct ltt_trace_struct *new_trace = NULL; - prepare_chan_size_num(&subbuf_size_low, &n_subbufs_low, - LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW); + ltt_lock_traces(); - prepare_chan_size_num(&subbuf_size_med, &n_subbufs_med, - LTT_DEFAULT_SUBBUF_SIZE_MED, LTT_DEFAULT_N_SUBBUFS_MED); + if (_ltt_trace_find_setup(trace_name)) { + printk(KERN_ERR "LTT : Trace name %s already used.\n", + trace_name); + err = -EEXIST; + goto traces_error; + } - prepare_chan_size_num(&subbuf_size_high, &n_subbufs_high, - LTT_DEFAULT_SUBBUF_SIZE_HIGH, LTT_DEFAULT_N_SUBBUFS_HIGH); + if (_ltt_trace_find(trace_name)) { + printk(KERN_ERR "LTT : Trace name %s already used.\n", + trace_name); + err = -EEXIST; + goto traces_error; + } new_trace = kzalloc(sizeof(struct ltt_trace_struct), GFP_KERNEL); if (!new_trace) { printk(KERN_ERR "LTT : Unable to allocate memory for trace %s\n", trace_name); - err = ENOMEM; - goto traces_error; + err = -ENOMEM; + goto trace_free; } - kref_init(&new_trace->kref); - kref_init(&new_trace->ltt_transport_kref); - init_waitqueue_head(&new_trace->kref_wq); - new_trace->active = 0; strncpy(new_trace->trace_name, trace_name, NAME_MAX); - new_trace->mode = mode; - new_trace->freq_scale = trace_clock_freq_scale(); + list_add(&new_trace->list, <t_traces.prealloc_head); + + ltt_unlock_traces(); + + return 0; + +trace_free: + kfree(new_trace); +traces_error: + ltt_unlock_traces(); + return err; +} + +/* must be called from within a traces lock. */ +static void _ltt_trace_free(struct ltt_trace_struct *trace) +{ + list_del(&trace->list); + kfree(trace); +} + +static int ltt_trace_set_type(const char *trace_name, const char *trace_type) +{ + int err = 0; + struct ltt_trace_struct *trace; + struct ltt_transport *tran_iter, *transport = NULL; ltt_lock_traces(); - list_for_each_entry(tran, <t_transport_list, node) { - if (!strcmp(tran->name, trace_type)) { - transport = tran; + + trace = _ltt_trace_find_setup(trace_name); + if (!trace) { + printk(KERN_ERR "LTT : Trace not found %s\n", trace_name); + err = -ENOENT; + goto traces_error; + } + + list_for_each_entry(tran_iter, <t_transport_list, node) { + if (!strcmp(tran_iter->name, trace_type)) { + transport = tran_iter; break; } } - if (!transport) { - err = EINVAL; printk(KERN_ERR "LTT : Transport %s is not present.\n", trace_type); - ltt_unlock_traces(); - goto trace_error; + err = -EINVAL; + goto traces_error; } - if (!try_module_get(transport->owner)) { - err = ENODEV; - printk(KERN_ERR "LTT : Can't lock transport module.\n"); - ltt_unlock_traces(); - goto trace_error; + trace->transport = transport; + +traces_error: + ltt_unlock_traces(); + return err; +} + +static int ltt_trace_set_mode(const char *trace_name, enum trace_mode mode) +{ + int err = 0; + struct ltt_trace_struct *trace; + + ltt_lock_traces(); + + trace = _ltt_trace_find_setup(trace_name); + if (!trace) { + printk(KERN_ERR "LTT : Trace not found %s\n", trace_name); + err = -ENOENT; + goto traces_error; } - trace = _ltt_trace_find(trace_name); - if (trace) { - printk(KERN_ERR "LTT : Trace name %s already used.\n", - trace_name); - err = EEXIST; - goto trace_error; + trace->mode = mode; + +traces_error: + ltt_unlock_traces(); + return err; +} + +/* + * Todo: + * Make similar function in channel.c, + * so it will be useful for both ltt-tracer.c and ltt-marker-control.c + */ +/* + * Its order is MUST be same with enum ltt_channels + */ +static char *chan_names[] = { + LTT_CPU_CHANNEL, + LTT_PROCESSES_CHANNEL, + LTT_INTERRUPTS_CHANNEL, + LTT_NETWORK_CHANNEL, + LTT_MODULES_CHANNEL, + LTT_METADATA_CHANNEL, +}; + +static enum ltt_channels get_channel_type_from_name(const char *name) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(chan_names); i++) + if (!strcmp(name, chan_names[i])) + return (enum ltt_channels)i; + + return NR_LTT_CHANNELS; +} + +static int ltt_trace_set_channel_subbufsize(const char *trace_name, + const char *channel_name, unsigned size) +{ + int err = 0; + struct ltt_trace_struct *trace; + enum ltt_channels channel; + + ltt_lock_traces(); + + trace = _ltt_trace_find_setup(trace_name); + if (!trace) { + printk(KERN_ERR "LTT : Trace not found %s\n", trace_name); + err = -ENOENT; + goto traces_error; } - new_trace->transport = transport; - new_trace->ops = &transport->ops; + channel = get_channel_type_from_name(channel_name); + if (channel == NR_LTT_CHANNELS) { + printk(KERN_ERR "LTT : Channel %s is not present.\n", + channel_name); + err = -EINVAL; + goto traces_error; + } - err = new_trace->ops->create_dirs(new_trace); - if (err) + trace->setting.channels[channel].subbuf_size = size; + +traces_error: + ltt_unlock_traces(); + return err; +} + +static int ltt_trace_set_channel_subbufcount(const char *trace_name, + const char *channel_name, unsigned cnt) +{ + int err = 0; + struct ltt_trace_struct *trace; + enum ltt_channels channel; + + ltt_lock_traces(); + + trace = _ltt_trace_find_setup(trace_name); + if (!trace) { + printk(KERN_ERR "LTT : Trace not found %s\n", trace_name); + err = -ENOENT; + goto traces_error; + } + + channel = get_channel_type_from_name(channel_name); + if (channel == NR_LTT_CHANNELS) { + printk(KERN_ERR "LTT : Channel %s is not present.\n", + channel_name); + err = -EINVAL; + goto traces_error; + } + + trace->setting.channels[channel].subbuf_cnt = cnt; + +traces_error: + ltt_unlock_traces(); + return err; +} + +static int ltt_trace_alloc(const char *trace_name) +{ + int err = 0; + struct ltt_trace_struct *trace; + int subbuf_size, subbuf_cnt; + unsigned long flags; + + ltt_lock_traces(); + + trace = _ltt_trace_find_setup(trace_name); + if (!trace) { + printk(KERN_ERR "LTT : Trace not found %s\n", trace_name); + err = -ENOENT; + goto traces_error; + } + + kref_init(&trace->kref); + kref_init(&trace->ltt_transport_kref); + init_waitqueue_head(&trace->kref_wq); + trace->active = 0; + trace->freq_scale = trace_clock_freq_scale(); + + if (!trace->transport) { + printk(KERN_ERR "LTT : Transport is not set.\n"); + err = -EINVAL; + goto traces_error; + } + if (!try_module_get(trace->transport->owner)) { + printk(KERN_ERR "LTT : Can't lock transport module.\n"); + err = -ENODEV; + goto traces_error; + } + trace->ops = &trace->transport->ops; + + err = trace->ops->create_dirs(trace); + if (err) { + printk(KERN_ERR "LTT : Can't create dir for trace %s.\n", + trace_name); goto dirs_error; + } local_irq_save(flags); - new_trace->start_freq = trace_clock_frequency(); - new_trace->start_tsc = trace_clock_read64(); - do_gettimeofday(&new_trace->start_time); + trace->start_freq = trace_clock_frequency(); + trace->start_tsc = trace_clock_read64(); + do_gettimeofday(&trace->start_time); local_irq_restore(flags); /* + * Todo: + * Config each channel's default buffersize/cnt, instead of + * LTT_DEFAULT_SUBBUF_SIZE_LOW, ... + */ + + /* * Always put the metadata channel in non-overwrite mode : * This is a very low traffic channel and it can't afford to have its * data overwritten : this data (marker info) is necessary to be * able to read the trace. */ - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.control_root, + subbuf_size = trace->setting.channels[LTT_CHANNEL_METADATA].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_METADATA].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.control_root, LTT_METADATA_CHANNEL, - &new_trace->channel.metadata, subbuf_size_low, - n_subbufs_low, - is_channel_overwrite(LTT_CHANNEL_METADATA, mode)); - if (err != 0) + &trace->channel.metadata, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_METADATA, + trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_METADATA]); goto metadata_error; - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.control_root, + } + + subbuf_size = + trace->setting.channels[LTT_CHANNEL_INTERRUPTS].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_INTERRUPTS].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.control_root, LTT_INTERRUPTS_CHANNEL, - &new_trace->channel.interrupts, subbuf_size_low, - n_subbufs_low, - is_channel_overwrite(LTT_CHANNEL_INTERRUPTS, mode)); - if (err != 0) + &trace->channel.interrupts, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_INTERRUPTS, + trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_INTERRUPTS]); goto interrupts_error; - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.control_root, + } + + subbuf_size = + trace->setting.channels[LTT_CHANNEL_PROCESSES].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_PROCESSES].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_MED, LTT_DEFAULT_N_SUBBUFS_MED); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.control_root, LTT_PROCESSES_CHANNEL, - &new_trace->channel.processes, subbuf_size_med, - n_subbufs_med, - is_channel_overwrite(LTT_CHANNEL_PROCESSES, mode)); - if (err != 0) + &trace->channel.processes, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_PROCESSES, + trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_PROCESSES]); goto processes_error; - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.control_root, + } + + subbuf_size = trace->setting.channels[LTT_CHANNEL_MODULES].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_MODULES].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.control_root, LTT_MODULES_CHANNEL, - &new_trace->channel.modules, subbuf_size_low, - n_subbufs_low, - is_channel_overwrite(LTT_CHANNEL_MODULES, mode)); - if (err != 0) + &trace->channel.modules, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_MODULES, trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_MODULES]); goto modules_error; - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.control_root, + } + + subbuf_size = trace->setting.channels[LTT_CHANNEL_NETWORK].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_NETWORK].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_LOW, LTT_DEFAULT_N_SUBBUFS_LOW); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.control_root, LTT_NETWORK_CHANNEL, - &new_trace->channel.network, subbuf_size_low, - n_subbufs_low, - is_channel_overwrite(LTT_CHANNEL_NETWORK, mode)); - if (err != 0) + &trace->channel.network, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_NETWORK, trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_NETWORK]); goto network_error; - err = new_trace->ops->create_channel(trace_name, new_trace, - new_trace->dentry.trace_root, + } + + subbuf_size = trace->setting.channels[LTT_CHANNEL_CPU].subbuf_size; + subbuf_cnt = trace->setting.channels[LTT_CHANNEL_CPU].subbuf_cnt; + prepare_chan_size_num(&subbuf_size, &subbuf_cnt, + LTT_DEFAULT_SUBBUF_SIZE_HIGH, LTT_DEFAULT_N_SUBBUFS_HIGH); + err = trace->ops->create_channel(trace_name, trace, + trace->dentry.trace_root, LTT_CPU_CHANNEL, - &new_trace->channel.cpu, subbuf_size_high, - n_subbufs_high, - is_channel_overwrite(LTT_CHANNEL_CPU, mode)); - if (err != 0) + &trace->channel.cpu, + subbuf_size, + subbuf_cnt, + is_channel_overwrite(LTT_CHANNEL_CPU, trace->mode)); + if (err != 0) { + printk(KERN_ERR "LTT : Can't create channel %s.\n", + chan_names[LTT_CHANNEL_CPU]); goto cpu_error; + } - err = _ltt_trace_create(trace_name, mode, new_trace); + list_del(&trace->list); + if (list_empty(<t_traces.head)) { + probe_id_defrag(); + mod_timer(<t_async_wakeup_timer, + jiffies + LTT_PERCPU_TIMER_INTERVAL); + set_kernel_trace_flag_all_tasks(); + } + list_add_rcu(&trace->list, <t_traces.head); + synchronize_sched(); - if (err != 0) - goto lock_create_error; ltt_unlock_traces(); - return err; -lock_create_error: - new_trace->ops->remove_channel(new_trace->channel.cpu); + return 0; + cpu_error: - new_trace->ops->remove_channel(new_trace->channel.network); + trace->ops->remove_channel(trace->channel.network); network_error: - new_trace->ops->remove_channel(new_trace->channel.modules); + trace->ops->remove_channel(trace->channel.modules); modules_error: - new_trace->ops->remove_channel(new_trace->channel.processes); + trace->ops->remove_channel(trace->channel.processes); processes_error: - new_trace->ops->remove_channel(new_trace->channel.interrupts); + trace->ops->remove_channel(trace->channel.interrupts); interrupts_error: - new_trace->ops->remove_channel(new_trace->channel.metadata); + trace->ops->remove_channel(trace->channel.metadata); metadata_error: - kref_put(&new_trace->ltt_transport_kref, ltt_release_transport); + trace->ops->remove_dirs(trace); dirs_error: - module_put(transport->owner); -trace_error: - kref_put(&new_trace->kref, ltt_release_trace); - wake_up_interruptible(&new_trace->kref_wq); - ltt_unlock_traces(); + module_put(trace->transport->owner); traces_error: + ltt_unlock_traces(); + return err; +} + +/* + * It is worked as a wrapper for current version of ltt_control.ko. + * We will make a new ltt_control based on debugfs, and control each channel's + * buffer. + */ +static int ltt_trace_create(const char *trace_name, const char *trace_type, + enum trace_mode mode, + unsigned subbuf_size_low, unsigned n_subbufs_low, + unsigned subbuf_size_med, unsigned n_subbufs_med, + unsigned subbuf_size_high, unsigned n_subbufs_high) +{ + int err = 0; + + err = ltt_trace_setup(trace_name); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_type(trace_name, trace_type); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_mode(trace_name, mode); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, + LTT_METADATA_CHANNEL, subbuf_size_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, + LTT_METADATA_CHANNEL, n_subbufs_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, + LTT_INTERRUPTS_CHANNEL, subbuf_size_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, + LTT_INTERRUPTS_CHANNEL, n_subbufs_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, + LTT_PROCESSES_CHANNEL, subbuf_size_med); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, + LTT_PROCESSES_CHANNEL, n_subbufs_med); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, LTT_MODULES_CHANNEL, + subbuf_size_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, LTT_MODULES_CHANNEL, + n_subbufs_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, LTT_NETWORK_CHANNEL, + subbuf_size_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, LTT_NETWORK_CHANNEL, + n_subbufs_low); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufsize(trace_name, LTT_CPU_CHANNEL, + subbuf_size_high); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_set_channel_subbufcount(trace_name, LTT_CPU_CHANNEL, + n_subbufs_high); + if (IS_ERR_VALUE(err)) + return err; + + err = ltt_trace_alloc(trace_name); + if (IS_ERR_VALUE(err)) + return err; + return err; } @@ -817,6 +1127,12 @@ static void __exit ltt_exit(void) _ltt_trace_destroy(trace); __ltt_trace_destroy(trace); } + /* free traces in pre-alloc status */ + list_for_each_safe(pos, n, <t_traces.prealloc_head) { + trace = container_of(pos, struct ltt_trace_struct, list); + _ltt_trace_free(trace); + } + ltt_unlock_traces(); } -- 1.5.5.3