ring-buffer: Have rb_time_cmpxchg() set the msb counter too
[platform/kernel/linux-starfive.git] / kernel / trace / ring_buffer.c
index 515cafd..af08a1a 100644 (file)
@@ -644,8 +644,8 @@ static inline bool __rb_time_read(rb_time_t *t, u64 *ret, unsigned long *cnt)
 
        *cnt = rb_time_cnt(top);
 
-       /* If top and bottom counts don't match, this interrupted a write */
-       if (*cnt != rb_time_cnt(bottom))
+       /* If top and msb counts don't match, this interrupted a write */
+       if (*cnt != rb_time_cnt(msb))
                return false;
 
        /* The shift to msb will lose its cnt bits */
@@ -706,6 +706,9 @@ static bool rb_time_cmpxchg(rb_time_t *t, u64 expect, u64 set)
        unsigned long cnt2, top2, bottom2, msb2;
        u64 val;
 
+       /* Any interruptions in this function should cause a failure */
+       cnt = local_read(&t->cnt);
+
        /* The cmpxchg always fails if it interrupted an update */
         if (!__rb_time_read(t, &val, &cnt2))
                 return false;
@@ -713,17 +716,18 @@ static bool rb_time_cmpxchg(rb_time_t *t, u64 expect, u64 set)
         if (val != expect)
                 return false;
 
-        cnt = local_read(&t->cnt);
         if ((cnt & 3) != cnt2)
                 return false;
 
         cnt2 = cnt + 1;
 
         rb_time_split(val, &top, &bottom, &msb);
+        msb = rb_time_val_cnt(msb, cnt);
         top = rb_time_val_cnt(top, cnt);
         bottom = rb_time_val_cnt(bottom, cnt);
 
         rb_time_split(set, &top2, &bottom2, &msb2);
+        msb2 = rb_time_val_cnt(msb2, cnt);
         top2 = rb_time_val_cnt(top2, cnt2);
         bottom2 = rb_time_val_cnt(bottom2, cnt2);
 
@@ -1787,6 +1791,8 @@ static void rb_free_cpu_buffer(struct ring_buffer_per_cpu *cpu_buffer)
                free_buffer_page(bpage);
        }
 
+       free_page((unsigned long)cpu_buffer->free_page);
+
        kfree(cpu_buffer);
 }
 
@@ -2407,7 +2413,7 @@ rb_iter_head_event(struct ring_buffer_iter *iter)
         */
        barrier();
 
-       if ((iter->head + length) > commit || length > BUF_MAX_DATA_SIZE)
+       if ((iter->head + length) > commit || length > BUF_PAGE_SIZE)
                /* Writer corrupted the read? */
                goto reset;
 
@@ -3030,23 +3036,20 @@ rb_try_to_discard(struct ring_buffer_per_cpu *cpu_buffer,
                        local_read(&bpage->write) & ~RB_WRITE_MASK;
                unsigned long event_length = rb_event_length(event);
 
+               /*
+                * For the before_stamp to be different than the write_stamp
+                * to make sure that the next event adds an absolute
+                * value and does not rely on the saved write stamp, which
+                * is now going to be bogus.
+                */
+               rb_time_set(&cpu_buffer->before_stamp, 0);
+
                /* Something came in, can't discard */
                if (!rb_time_cmpxchg(&cpu_buffer->write_stamp,
                                       write_stamp, write_stamp - delta))
                        return false;
 
                /*
-                * It's possible that the event time delta is zero
-                * (has the same time stamp as the previous event)
-                * in which case write_stamp and before_stamp could
-                * be the same. In such a case, force before_stamp
-                * to be different than write_stamp. It doesn't
-                * matter what it is, as long as its different.
-                */
-               if (!delta)
-                       rb_time_set(&cpu_buffer->before_stamp, 0);
-
-               /*
                 * If an event were to come in now, it would see that the
                 * write_stamp and the before_stamp are different, and assume
                 * that this event just added itself before updating
@@ -3582,7 +3585,10 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
                 * absolute timestamp.
                 * Don't bother if this is the start of a new page (w == 0).
                 */
-               if (unlikely(!a_ok || !b_ok || (info->before != info->after && w))) {
+               if (!w) {
+                       /* Use the sub-buffer timestamp */
+                       info->delta = 0;
+               } else if (unlikely(!a_ok || !b_ok || info->before != info->after)) {
                        info->add_timestamp |= RB_ADD_STAMP_FORCE | RB_ADD_STAMP_EXTEND;
                        info->length += RB_LEN_TIME_EXTEND;
                } else {
@@ -3605,26 +3611,19 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
 
        /* See if we shot pass the end of this buffer page */
        if (unlikely(write > BUF_PAGE_SIZE)) {
-               /* before and after may now different, fix it up*/
-               b_ok = rb_time_read(&cpu_buffer->before_stamp, &info->before);
-               a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
-               if (a_ok && b_ok && info->before != info->after)
-                       (void)rb_time_cmpxchg(&cpu_buffer->before_stamp,
-                                             info->before, info->after);
-               if (a_ok && b_ok)
-                       check_buffer(cpu_buffer, info, CHECK_FULL_PAGE);
+               check_buffer(cpu_buffer, info, CHECK_FULL_PAGE);
                return rb_move_tail(cpu_buffer, tail, info);
        }
 
        if (likely(tail == w)) {
-               u64 save_before;
-               bool s_ok;
-
                /* Nothing interrupted us between A and C */
  /*D*/         rb_time_set(&cpu_buffer->write_stamp, info->ts);
-               barrier();
- /*E*/         s_ok = rb_time_read(&cpu_buffer->before_stamp, &save_before);
-               RB_WARN_ON(cpu_buffer, !s_ok);
+               /*
+                * If something came in between C and D, the write stamp
+                * may now not be in sync. But that's fine as the before_stamp
+                * will be different and then next event will just be forced
+                * to use an absolute timestamp.
+                */
                if (likely(!(info->add_timestamp &
                             (RB_ADD_STAMP_FORCE | RB_ADD_STAMP_ABSOLUTE))))
                        /* This did not interrupt any time update */
@@ -3632,24 +3631,7 @@ __rb_reserve_next(struct ring_buffer_per_cpu *cpu_buffer,
                else
                        /* Just use full timestamp for interrupting event */
                        info->delta = info->ts;
-               barrier();
                check_buffer(cpu_buffer, info, tail);
-               if (unlikely(info->ts != save_before)) {
-                       /* SLOW PATH - Interrupted between C and E */
-
-                       a_ok = rb_time_read(&cpu_buffer->write_stamp, &info->after);
-                       RB_WARN_ON(cpu_buffer, !a_ok);
-
-                       /* Write stamp must only go forward */
-                       if (save_before > info->after) {
-                               /*
-                                * We do not care about the result, only that
-                                * it gets updated atomically.
-                                */
-                               (void)rb_time_cmpxchg(&cpu_buffer->write_stamp,
-                                                     info->after, save_before);
-                       }
-               }
        } else {
                u64 ts;
                /* SLOW PATH - Interrupted between A and C */
@@ -3740,6 +3722,8 @@ rb_reserve_next_event(struct trace_buffer *buffer,
        if (ring_buffer_time_stamp_abs(cpu_buffer->buffer)) {
                add_ts_default = RB_ADD_STAMP_ABSOLUTE;
                info.length += RB_LEN_TIME_EXTEND;
+               if (info.length > BUF_MAX_DATA_SIZE)
+                       goto out_fail;
        } else {
                add_ts_default = RB_ADD_STAMP_NONE;
        }
@@ -5121,7 +5105,8 @@ ring_buffer_read_prepare(struct trace_buffer *buffer, int cpu, gfp_t flags)
        if (!iter)
                return NULL;
 
-       iter->event = kmalloc(BUF_MAX_DATA_SIZE, flags);
+       /* Holds the entire event: data and meta data */
+       iter->event = kmalloc(BUF_PAGE_SIZE, flags);
        if (!iter->event) {
                kfree(iter);
                return NULL;