X-Git-Url: http://git.lttng.org/?a=blobdiff_plain;f=libust%2Frelay.c;h=408ce906f82c7f0262d71c2ea59270790f82b052;hb=a2dc02e0e0a685b8814b68a2f07ce73c08e0ef50;hp=6bb5a35d63d6aaed2497e0920287801b9e49d4a3;hpb=b4512257eb71d0432554047acf6278dc42a15a75;p=ust.git diff --git a/libust/relay.c b/libust/relay.c index 6bb5a35..408ce90 100644 --- a/libust/relay.c +++ b/libust/relay.c @@ -22,14 +22,15 @@ //ust// #include //ust// #include //ust// #include -#include "kernelcompat.h" +#include #include #include #include -#include "list.h" +#include +//#include "list.h" #include "relay.h" #include "channels.h" -#include "kref.h" +#include #include "tracer.h" #include "tracercore.h" #include "usterr.h" @@ -101,7 +102,11 @@ static int relay_alloc_buf(struct rchan_buf *buf, size_t *size) *size = PAGE_ALIGN(*size); result = buf->shmid = shmget(getpid(), *size, IPC_CREAT | IPC_EXCL | 0700); - if(buf->shmid == -1) { + if(result == -1 && errno == EINVAL) { + ERR("shmget() returned EINVAL; maybe /proc/sys/kernel/shmmax should be increased."); + return -1; + } + else if(result == -1) { PERROR("shmget"); return -1; } @@ -182,7 +187,7 @@ static void relay_destroy_channel(struct kref *kref) static void relay_destroy_buf(struct rchan_buf *buf) { struct rchan *chan = buf->chan; - struct buf_page *buf_page, *n; +//ust// struct buf_page *buf_page; int result; result = munmap(buf->buf_data, buf->buf_size); @@ -222,21 +227,21 @@ static void relay_remove_buf(struct kref *kref) /* * create_buf_file_create() default callback. Does nothing. */ -static struct dentry *create_buf_file_default_callback(const char *filename, - struct dentry *parent, - int mode, - struct rchan_buf *buf) -{ - return NULL; -} +//ust// static struct dentry *create_buf_file_default_callback(const char *filename, +//ust// struct dentry *parent, +//ust// int mode, +//ust// struct rchan_buf *buf) +//ust// { +//ust// return NULL; +//ust// } -/* - * remove_buf_file() default callback. Does nothing. - */ -static int remove_buf_file_default_callback(struct dentry *dentry) -{ - return -EINVAL; -} +//ust// /* +//ust// * remove_buf_file() default callback. Does nothing. +//ust// */ +//ust// static int remove_buf_file_default_callback(struct dentry *dentry) +//ust// { +//ust// return -EINVAL; +//ust// } /** * wakeup_readers - wake up readers waiting on a channel @@ -263,7 +268,7 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init) //ust// init_waitqueue_head(&buf->read_wait); kref_init(&buf->kref); //ust// setup_timer(&buf->timer, wakeup_readers, (unsigned long)buf); - } else + } //ust// else //ust// del_timer_sync(&buf->timer); buf->finalized = 0; @@ -277,7 +282,7 @@ static void __relay_reset(struct rchan_buf *buf, unsigned int init) static struct rchan_buf *relay_open_buf(struct rchan *chan) { struct rchan_buf *buf = NULL; - struct dentry *dentry; +//ust// struct dentry *dentry; //ust// char *tmpname; //ust// tmpname = kzalloc(NAME_MAX + 1, GFP_KERNEL); @@ -304,12 +309,12 @@ static struct rchan_buf *relay_open_buf(struct rchan *chan) goto free_name; -free_buf: +//ust//free_buf: relay_destroy_buf(buf); buf = NULL; free_name: //ust// kfree(tmpname); -end: +//ust//end: return buf; } @@ -406,7 +411,7 @@ struct rchan *ltt_relay_open(const char *base_filename, size_t n_subbufs, void *private_data) { - unsigned int i; +//ust// unsigned int i; struct rchan *chan; //ust// if (!base_filename) //ust// return NULL; @@ -462,7 +467,7 @@ struct rchan *ltt_relay_open(const char *base_filename, */ void ltt_relay_close(struct rchan *chan) { - unsigned int i; +//ust// unsigned int i; if (!chan) return; @@ -887,13 +892,18 @@ void relay_wake_consumer(void *arg, int finished) } static notrace void ltt_deliver(struct rchan_buf *buf, unsigned int subbuf_idx, - void *subbuf) + long commit_count) { struct ltt_channel_struct *channel = (struct ltt_channel_struct *)buf->chan->private_data; struct ltt_channel_buf_struct *ltt_buf = channel->buf; int result; +//ust// #ifdef CONFIG_LTT_VMCORE + local_set(<t_buf->commit_seq[subbuf_idx], commit_count); +//ust// #endif + + /* wakeup consumer */ result = write(ltt_buf->data_ready_fd_write, "1", 1); if(result == -1) { PERROR("write (in ltt_relay_buffer_flush)"); @@ -924,16 +934,16 @@ static struct dentry *ltt_create_buf_file_callback(struct rchan_buf *buf) return NULL; } -static int ltt_remove_buf_file_callback(struct rchan_buf *buf) -{ -//ust// struct rchan_buf *buf = dentry->d_inode->i_private; - struct ltt_channel_struct *ltt_chan = buf->chan->private_data; - -//ust// debugfs_remove(dentry); - ltt_relay_destroy_buffer(ltt_chan); - - return 0; -} +//ust// static int ltt_remove_buf_file_callback(struct rchan_buf *buf) +//ust// { +//ust// //ust// struct rchan_buf *buf = dentry->d_inode->i_private; +//ust// struct ltt_channel_struct *ltt_chan = buf->chan->private_data; +//ust// +//ust// //ust// debugfs_remove(dentry); +//ust// ltt_relay_destroy_buffer(ltt_chan); +//ust// +//ust// return 0; +//ust// } /* * Wake writers : @@ -1463,10 +1473,10 @@ static int ltt_relay_create_buffer(struct ltt_trace_struct *trace, int fds[2]; int result; -//ust// ltt_buf->commit_count = -//ust// zmalloc(sizeof(ltt_buf->commit_count) * n_subbufs); -//ust// if (!ltt_buf->commit_count) -//ust// return -ENOMEM; + ltt_buf->commit_count = + zmalloc(sizeof(ltt_buf->commit_count) * n_subbufs); + if (!ltt_buf->commit_count) + return -ENOMEM; kref_get(&trace->kref); kref_get(&trace->ltt_transport_kref); kref_get(<t_chan->kref); @@ -1494,6 +1504,19 @@ static int ltt_relay_create_buffer(struct ltt_trace_struct *trace, ltt_buf->data_ready_fd_read = fds[0]; ltt_buf->data_ready_fd_write = fds[1]; + /* FIXME: do we actually need this? */ + result = fcntl(fds[0], F_SETFL, O_NONBLOCK); + if(result == -1) { + PERROR("fcntl"); + } + +//ust// ltt_buf->commit_seq = malloc(sizeof(ltt_buf->commit_seq) * n_subbufs); +//ust// if(!ltt_buf->commit_seq) { +//ust// return -1; +//ust// } + + /* FIXME: decrementally destroy on error */ + return 0; } @@ -1505,8 +1528,9 @@ static void ltt_relay_destroy_buffer(struct ltt_channel_struct *ltt_chan) kref_put(<t_chan->trace->ltt_transport_kref, ltt_release_transport); ltt_relay_print_buffer_errors(ltt_chan); -//ust// kfree(ltt_buf->commit_count); -//ust// ltt_buf->commit_count = NULL; +//ust// free(ltt_buf->commit_seq); + kfree(ltt_buf->commit_count); + ltt_buf->commit_count = NULL; kref_put(<t_chan->kref, ltt_relay_release_channel); kref_put(&trace->kref, ltt_release_trace); //ust// wake_up_interruptible(&trace->kref_wq); @@ -1518,13 +1542,13 @@ static void ltt_chan_alloc_ltt_buf(struct ltt_channel_struct *ltt_chan) int result; /* Get one page */ - /* FIXME: increase size if we have a commit_count array that overflows the page */ + /* FIXME: increase size if we have a seq_commit array that overflows the page */ size_t size = PAGE_ALIGN(1); result = ltt_chan->buf_shmid = shmget(getpid(), size, IPC_CREAT | IPC_EXCL | 0700); if(ltt_chan->buf_shmid == -1) { PERROR("shmget"); - return -1; + return; } ptr = shmat(ltt_chan->buf_shmid, NULL, 0); @@ -1539,12 +1563,12 @@ static void ltt_chan_alloc_ltt_buf(struct ltt_channel_struct *ltt_chan) result = shmctl(ltt_chan->buf_shmid, IPC_RMID, NULL); if(result == -1) { perror("shmctl"); - return -1; + return; } ltt_chan->buf = ptr; - return 0; + return; destroy_shmem: result = shmctl(ltt_chan->buf_shmid, IPC_RMID, NULL); @@ -1552,7 +1576,7 @@ static void ltt_chan_alloc_ltt_buf(struct ltt_channel_struct *ltt_chan) perror("shmctl"); } - return -1; + return; } /* @@ -1681,7 +1705,7 @@ static void ltt_relay_async_wakeup_chan(struct ltt_channel_struct *ltt_channel) static void ltt_relay_finish_buffer(struct ltt_channel_struct *ltt_channel) { struct rchan *rchan = ltt_channel->trans_channel_data; - int result; +// int result; if (rchan->buf) { struct ltt_channel_buf_struct *ltt_buf = ltt_channel->buf; @@ -1701,7 +1725,7 @@ static void ltt_relay_finish_buffer(struct ltt_channel_struct *ltt_channel) static void ltt_relay_finish_channel(struct ltt_channel_struct *ltt_channel) { - unsigned int i; +//ust// unsigned int i; //ust// for_each_possible_cpu(i) ltt_relay_finish_buffer(ltt_channel); @@ -1774,13 +1798,24 @@ static inline int ltt_relay_try_reserve( - (local_read(<t_buf->commit_count[subbuf_index]) & ltt_channel->commit_count_mask); if (offsets->reserve_commit_diff == 0) { + long consumed; + + consumed = atomic_long_read(<t_buf->consumed); + /* Next buffer not corrupted. */ if (!ltt_channel->overwrite && (SUBBUF_TRUNC(offsets->begin, buf->chan) - - SUBBUF_TRUNC(atomic_long_read( - <t_buf->consumed), - buf->chan)) + - SUBBUF_TRUNC(consumed, buf->chan)) >= rchan->alloc_size) { + + long consumed_idx = SUBBUF_INDEX(consumed, buf->chan); + long commit_count = local_read(<t_buf->commit_count[consumed_idx]); + if(((commit_count - buf->chan->subbuf_size) & ltt_channel->commit_count_mask) - (BUFFER_TRUNC(consumed, buf->chan) >> ltt_channel->n_subbufs_order) != 0) { + WARN("Event dropped. Caused by non-committed event."); + } + else { + WARN("Event dropped. Caused by non-consumed buffer."); + } /* * We do not overwrite non consumed buffers * and we are full : event is lost. @@ -2016,7 +2051,7 @@ static inline void ltt_reserve_switch_old_subbuf( >> ltt_channel->n_subbufs_order) - ((offsets->commit_count - rchan->subbuf_size) & ltt_channel->commit_count_mask) == 0) - ltt_deliver(buf, oldidx, NULL); + ltt_deliver(buf, oldidx, offsets->commit_count); } /* @@ -2044,7 +2079,7 @@ static /*inline*/ void ltt_reserve_switch_new_subbuf( >> ltt_channel->n_subbufs_order) - ((offsets->commit_count - rchan->subbuf_size) & ltt_channel->commit_count_mask) == 0) - ltt_deliver(buf, beginidx, NULL); + ltt_deliver(buf, beginidx, offsets->commit_count); } @@ -2086,7 +2121,7 @@ static inline void ltt_reserve_end_switch_current( >> ltt_channel->n_subbufs_order) - ((offsets->commit_count - rchan->subbuf_size) & ltt_channel->commit_count_mask) == 0) - ltt_deliver(buf, endidx, NULL); + ltt_deliver(buf, endidx, offsets->commit_count); } /** @@ -2229,96 +2264,6 @@ static notrace void ltt_force_switch(struct rchan_buf *buf, ltt_buf, rchan, buf, &offsets, &tsc); } -/* - * for flight recording. must be called after relay_commit. - * This function decrements de subbuffer's lost_size each time the commit count - * reaches back the reserve offset (module subbuffer size). It is useful for - * crash dump. - * We use slot_size - 1 to make sure we deal correctly with the case where we - * fill the subbuffer completely (so the subbuf index stays in the previous - * subbuffer). - */ -//ust// #ifdef CONFIG_LTT_VMCORE -static /*inline*/ void ltt_write_commit_counter(struct rchan_buf *buf, - long buf_offset, size_t slot_size) -{ - struct ltt_channel_struct *ltt_channel = - (struct ltt_channel_struct *)buf->chan->private_data; - struct ltt_channel_buf_struct *ltt_buf = ltt_channel->buf; - struct ltt_subbuffer_header *header; - long offset, subbuf_idx, commit_count; - uint32_t lost_old, lost_new; - - subbuf_idx = SUBBUF_INDEX(buf_offset - 1, buf->chan); - offset = buf_offset + slot_size; - header = (struct ltt_subbuffer_header *) - ltt_relay_offset_address(buf, - subbuf_idx * buf->chan->subbuf_size); - for (;;) { - lost_old = header->lost_size; - commit_count = - local_read(<t_buf->commit_count[subbuf_idx]); - /* SUBBUF_OFFSET includes commit_count_mask */ - if (!SUBBUF_OFFSET(offset - commit_count, buf->chan)) { - lost_new = (uint32_t)buf->chan->subbuf_size - - SUBBUF_OFFSET(commit_count, buf->chan); - lost_old = cmpxchg_local(&header->lost_size, lost_old, - lost_new); - if (lost_old <= lost_new) - break; - } else { - break; - } - } -} -//ust// #else -//ust// static inline void ltt_write_commit_counter(struct rchan_buf *buf, -//ust// long buf_offset, size_t slot_size) -//ust// { -//ust// } -//ust// #endif - -/* - * Atomic unordered slot commit. Increments the commit count in the - * specified sub-buffer, and delivers it if necessary. - * - * Parameters: - * - * @ltt_channel : channel structure - * @transport_data: transport-specific data - * @buf_offset : offset following the event header. - * @slot_size : size of the reserved slot. - */ -static notrace void ltt_relay_commit_slot( - struct ltt_channel_struct *ltt_channel, - void **transport_data, long buf_offset, size_t slot_size) -{ - struct rchan_buf *buf = *transport_data; - struct ltt_channel_buf_struct *ltt_buf = ltt_channel->buf; - struct rchan *rchan = buf->chan; - long offset_end = buf_offset; - long endidx = SUBBUF_INDEX(offset_end - 1, rchan); - long commit_count; - - /* Must write slot data before incrementing commit count */ - smp_wmb(); - commit_count = local_add_return(slot_size, - <t_buf->commit_count[endidx]); - /* Check if all commits have been done */ - if ((BUFFER_TRUNC(offset_end - 1, rchan) - >> ltt_channel->n_subbufs_order) - - ((commit_count - rchan->subbuf_size) - & ltt_channel->commit_count_mask) == 0) - ltt_deliver(buf, endidx, NULL); - /* - * Update lost_size for each commit. It's needed only for extracting - * ltt buffers from vmcore, after crash. - */ - ltt_write_commit_counter(buf, buf_offset, slot_size); - - DBG("commited slot. now commit count is %ld", commit_count); -} - /* * This is called with preemption disabled when user space has requested * blocking mode. If one of the active traces has free space below a @@ -2438,7 +2383,7 @@ static struct ltt_transport ust_relay_transport = { .finish_channel = ltt_relay_finish_channel, .remove_channel = ltt_relay_remove_channel, .wakeup_channel = ltt_relay_async_wakeup_chan, - .commit_slot = ltt_relay_commit_slot, +// .commit_slot = ltt_relay_commit_slot, .reserve_slot = ltt_relay_reserve_slot, .user_blocking = ltt_relay_user_blocking, .user_errors = ltt_relay_print_user_errors, @@ -2465,6 +2410,87 @@ static struct ltt_transport ust_relay_transport = { //ust// return 0; //ust// } +/* + * for flight recording. must be called after relay_commit. + * This function decrements de subbuffer's lost_size each time the commit count + * reaches back the reserve offset (module subbuffer size). It is useful for + * crash dump. + */ +//ust// #ifdef CONFIG_LTT_VMCORE +static /* inline */ void ltt_write_commit_counter(struct rchan_buf *buf, + struct ltt_channel_buf_struct *ltt_buf, + long idx, long buf_offset, long commit_count, size_t data_size) +{ + long offset; + long commit_seq_old; + + offset = buf_offset + data_size; + + /* + * SUBBUF_OFFSET includes commit_count_mask. We can simply + * compare the offsets within the subbuffer without caring about + * buffer full/empty mismatch because offset is never zero here + * (subbuffer header and event headers have non-zero length). + */ + if (unlikely(SUBBUF_OFFSET(offset - commit_count, buf->chan))) + return; + + commit_seq_old = local_read(<t_buf->commit_seq[idx]); + while (commit_seq_old < commit_count) + commit_seq_old = local_cmpxchg(<t_buf->commit_seq[idx], + commit_seq_old, commit_count); +} +//ust// #else +//ust// static inline void ltt_write_commit_counter(struct rchan_buf *buf, +//ust// long buf_offset, size_t slot_size) +//ust// { +//ust// } +//ust// #endif + +/* + * Atomic unordered slot commit. Increments the commit count in the + * specified sub-buffer, and delivers it if necessary. + * + * Parameters: + * + * @ltt_channel : channel structure + * @transport_data: transport-specific data + * @buf_offset : offset following the event header. + * @data_size : size of the event data. + * @slot_size : size of the reserved slot. + */ +/* FIXME: make this function static inline in the .h! */ +/*static*/ /* inline */ notrace void ltt_commit_slot( + struct ltt_channel_struct *ltt_channel, + void **transport_data, long buf_offset, + size_t data_size, size_t slot_size) +{ + struct rchan_buf *buf = *transport_data; + struct ltt_channel_buf_struct *ltt_buf = ltt_channel->buf; + struct rchan *rchan = buf->chan; + long offset_end = buf_offset; + long endidx = SUBBUF_INDEX(offset_end - 1, rchan); + long commit_count; + + /* Must write slot data before incrementing commit count */ + smp_wmb(); + commit_count = local_add_return(slot_size, + <t_buf->commit_count[endidx]); + /* Check if all commits have been done */ + if ((BUFFER_TRUNC(offset_end - 1, rchan) + >> ltt_channel->n_subbufs_order) + - ((commit_count - rchan->subbuf_size) + & ltt_channel->commit_count_mask) == 0) + ltt_deliver(buf, endidx, commit_count); + /* + * Update lost_size for each commit. It's needed only for extracting + * ltt buffers from vmcore, after crash. + */ + ltt_write_commit_counter(buf, ltt_buf, endidx, + buf_offset, commit_count, data_size); +} + + static char initialized = 0; void __attribute__((constructor)) init_ustrelay_transport(void) @@ -2475,7 +2501,7 @@ void __attribute__((constructor)) init_ustrelay_transport(void) } } -static void __exit ltt_relay_exit(void) +static void __attribute__((destructor)) ltt_relay_exit(void) { //ust// printk(KERN_INFO "LTT : ltt-relay exit\n");