improve error handling
[ust.git] / libust / relay.c
index 6bb5a35d63d6aaed2497e0920287801b9e49d4a3..3259adee432da29fb1b063605b1d7bab01be3255 100644 (file)
 #include <sys/mman.h>
 #include <sys/ipc.h>
 #include <sys/shm.h>
-#include "list.h"
+//#include "list.h"
 #include "relay.h"
 #include "channels.h"
-#include "kref.h"
+#include <kcompat/kref.h>
 #include "tracer.h"
 #include "tracercore.h"
 #include "usterr.h"
@@ -101,7 +101,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 +186,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 +226,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
@@ -277,7 +281,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 +308,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 +410,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 +466,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 +891,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(&ltt_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 +933,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 +1472,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(&ltt_chan->kref);
@@ -1494,6 +1503,13 @@ 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];
 
+//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 +1521,9 @@ static void ltt_relay_destroy_buffer(struct ltt_channel_struct *ltt_chan)
        kref_put(&ltt_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(&ltt_chan->kref, ltt_relay_release_channel);
        kref_put(&trace->kref, ltt_release_trace);
 //ust//        wake_up_interruptible(&trace->kref_wq);
@@ -1518,13 +1535,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 +1556,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 +1569,7 @@ static void ltt_chan_alloc_ltt_buf(struct ltt_channel_struct *ltt_chan)
                perror("shmctl");
        }
 
-       return -1;
+       return;
 }
 
 /*
@@ -1681,7 +1698,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 +1718,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);
@@ -2016,7 +2033,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 +2061,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 +2103,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 +2246,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(&ltt_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,
-               &ltt_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 +2365,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 +2392,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(&ltt_buf->commit_seq[idx]);
+       while (commit_seq_old < commit_count)
+               commit_seq_old = local_cmpxchg(&ltt_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,
+               &ltt_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 +2483,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");
 
This page took 0.029889 seconds and 4 git commands to generate.