On Fri 2014-11-07 13:30:17, Steven Rostedt wrote:
> 
> I'm not going to waist bandwidth reposting the entire series. Here's a
> new version of this patch. I'm getting ready to pull it into my next
> queue.
> 
> -- Steve
> 
> From 11674c8df0580a03a2517e3a8e4705c47c663564 Mon Sep 17 00:00:00 2001
> From: "Steven Rostedt (Red Hat)" <rost...@goodmis.org>
> Date: Wed, 25 Jun 2014 15:54:42 -0400
> Subject: [PATCH] tracing: Create seq_buf layer in trace_seq
> 
> Create a seq_buf layer that trace_seq sits on. The seq_buf will not
> be limited to page size. This will allow other usages of seq_buf
> instead of a hard set PAGE_SIZE one that trace_seq has.
> 
> Link: http://lkml.kernel.org/r/20141104160221.864997...@goodmis.org
> 
> Tested-by: Jiri Kosina <jkos...@suse.cz>
> Acked-by: Jiri Kosina <jkos...@suse.cz>
> Signed-off-by: Steven Rostedt <rost...@goodmis.org>
> ---
>  include/linux/seq_buf.h              |  78 ++++++++
>  include/linux/trace_seq.h            |  10 +-
>  kernel/trace/Makefile                |   1 +
>  kernel/trace/seq_buf.c               | 341 
> +++++++++++++++++++++++++++++++++++
>  kernel/trace/trace.c                 |  39 ++--
>  kernel/trace/trace_events.c          |   6 +-
>  kernel/trace/trace_functions_graph.c |   6 +-
>  kernel/trace/trace_seq.c             | 184 +++++++++----------
>  8 files changed, 540 insertions(+), 125 deletions(-)
>  create mode 100644 include/linux/seq_buf.h
>  create mode 100644 kernel/trace/seq_buf.c
> 
> diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
> new file mode 100644
> index 000000000000..64bf5a43411e
> --- /dev/null
> +++ b/include/linux/seq_buf.h
> @@ -0,0 +1,78 @@
> +#ifndef _LINUX_SEQ_BUF_H
> +#define _LINUX_SEQ_BUF_H
> +
> +#include <linux/fs.h>
> +
> +/*
> + * Trace sequences are used to allow a function to call several other 
> functions
> + * to create a string of data to use.
> + */
> +
> +/**
> + * seq_buf - seq buffer structure
> + * @buffer:  pointer to the buffer
> + * @size:    size of the buffer
> + * @len:     the amount of data inside the buffer
> + * @readpos: The next position to read in the buffer.
> + */
> +struct seq_buf {
> +     unsigned char           *buffer;
> +     unsigned int            size;
> +     unsigned int            len;
> +     unsigned int            readpos;
> +};
> +
> +static inline void
> +seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)
> +{
> +     s->buffer = buf;
> +     s->size = size;
> +     s->len = 0;
> +     s->readpos = 0;
> +}
> +
> +/*
> + * seq_buf have a buffer that might overflow. When this happens
> + * the len and size are set to be equal.
> + */
> +static inline bool
> +seq_buf_has_overflowed(struct seq_buf *s)
> +{
> +     return s->len == s->size;
> +}
> +
> +static inline void
> +seq_buf_set_overflow(struct seq_buf *s)
> +{
> +     s->len = s->size;
> +}
> +
> +/*
> + * How much buffer is left on the seq_buf?
> + */
> +static inline unsigned int
> +seq_buf_buffer_left(struct seq_buf *s)
> +{
> +     return (s->size - 1) - s->len;

This should be

        if (seq_buf_has_overflowed(s)
                return 0;
        return (s->size - 1) - s->len;

otherwise, it would return UNIT_MAX for the overflown state. If I am
not mistaken.

[...]

> diff --git a/kernel/trace/seq_buf.c b/kernel/trace/seq_buf.c
> new file mode 100644
> index 000000000000..88738b200bf3
> --- /dev/null
> +++ b/kernel/trace/seq_buf.c

[...]

> +
> +/**
> + * seq_buf_bitmask - write a bitmask array in its ASCII representation
> + * @s:               seq_buf descriptor
> + * @maskp:   points to an array of unsigned longs that represent a bitmask
> + * @nmaskbits:       The number of bits that are valid in @maskp
> + *
> + * Writes a ASCII representation of a bitmask string into @s.
> + *
> + * Returns zero on success, -1 on overflow.
> + */
> +int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
> +                 int nmaskbits)
> +{
> +     unsigned int len = seq_buf_buffer_left(s);
> +     int ret;
> +
> +     WARN_ON(s->size == 0);
> +
> +     /*
> +      * The last byte of the buffer is used to determine if we
> +      * overflowed or not.
> +      */
> +     if (len > 1) {
> +             ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);

It should be:

                ret = bitmap_scnprintf(s->buffer + s->len, len,
                                       maskp, nmaskbits);

otherwise, we would write to the beginning to the buffer.

> +             if (ret < len) {
> +                     s->len += ret;
> +                     return 0;
> +             }
> +     }
> +     seq_buf_set_overflow(s);
> +     return -1;
> +}
> +

[...]

> diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
> index 1f24ed99dca2..3ad8738aea19 100644
> --- a/kernel/trace/trace_seq.c
> +++ b/kernel/trace/trace_seq.c

[...]

> @@ -144,23 +160,24 @@ EXPORT_SYMBOL_GPL(trace_seq_bitmask);
>   */
>  int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
>  {
> -     unsigned int len = TRACE_SEQ_BUF_LEFT(s);
> +     unsigned int save_len = s->seq.len;
>       int ret;
>  
> -     if (s->full || !len)
> +     if (s->full)
>               return 0;
>  
> -     ret = vsnprintf(s->buffer + s->len, len, fmt, args);
> +     __trace_seq_init(s);
> +
> +     ret = seq_buf_vprintf(&s->seq, fmt, args);

Note that this returns 0 on success => we do not need to store it

>       /* If we can't write it all, don't bother writing anything */
> -     if (ret >= len) {
> +     if (unlikely(seq_buf_has_overflowed(&s->seq))) {
> +             s->seq.len = save_len;
>               s->full = 1;
>               return 0;
>       }
>  
> -     s->len += ret;
> -
> -     return len;
> +     return ret;

Instead, we have to do something like:

        return s->seq.len - save_len;

>  }
>  EXPORT_SYMBOL_GPL(trace_seq_vprintf);
>  
> @@ -183,23 +200,24 @@ EXPORT_SYMBOL_GPL(trace_seq_vprintf);
>   */
>  int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 
> *binary)
>  {
> -     unsigned int len = TRACE_SEQ_BUF_LEFT(s);
> +     unsigned int save_len = s->seq.len;
>       int ret;
>  
> -     if (s->full || !len)
> +     if (s->full)
>               return 0;
>  
> -     ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
> +     __trace_seq_init(s);
> +
> +     ret = seq_buf_bprintf(&s->seq, fmt, binary);

Same here, it returns 0 on success => no need to store.

>       /* If we can't write it all, don't bother writing anything */
> -     if (ret >= len) {
> +     if (unlikely(seq_buf_has_overflowed(&s->seq))) {
> +             s->seq.len = save_len;
>               s->full = 1;
>               return 0;
>       }
>  
> -     s->len += ret;
> -
> -     return len;
> +     return ret;

and

        return s->seq.len - save_len;

>  }
>  EXPORT_SYMBOL_GPL(trace_seq_bprintf);
>  

[...]

>  /**
>   * trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
>   * @s: trace sequence descriptor
> @@ -309,35 +328,30 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem);
>  int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
>                        unsigned int len)
>  {
> -     unsigned char hex[HEX_CHARS];
> -     const unsigned char *data = mem;
> -     unsigned int start_len;
> -     int i, j;
> -     int cnt = 0;
> +     unsigned int save_len = s->seq.len;
> +     int ret;
>  
>       if (s->full)
>               return 0;
>  
> -     while (len) {
> -             start_len = min(len, HEX_CHARS - 1);
> -#ifdef __BIG_ENDIAN
> -             for (i = 0, j = 0; i < start_len; i++) {
> -#else
> -             for (i = start_len-1, j = 0; i >= 0; i--) {
> -#endif
> -                     hex[j++] = hex_asc_hi(data[i]);
> -                     hex[j++] = hex_asc_lo(data[i]);
> -             }
> -             if (WARN_ON_ONCE(j == 0 || j/2 > len))
> -                     break;
> -
> -             /* j increments twice per loop */
> -             len -= j / 2;
> -             hex[j++] = ' ';
> -
> -             cnt += trace_seq_putmem(s, hex, j);
> +     __trace_seq_init(s);
> +
> +     /* Each byte is represented by two chars */
> +     if (len * 2 > TRACE_SEQ_BUF_LEFT(s)) {
> +             s->full = 1;
> +             return 0;
> +     }
> +
> +     /* The added spaces can still cause an overflow */
> +     ret = seq_buf_putmem_hex(&s->seq, mem, len);

and here, it returns zero on success

> +
> +     if (unlikely(seq_buf_has_overflowed(&s->seq))) {
> +             s->seq.len = save_len;
> +             s->full = 1;
> +             return 0;
>       }
> -     return cnt;
> +
> +     return ret;

Therefore we need something like:

        return s->seq.len - save_len;

>  }
>  EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);
>  
> @@ -355,30 +369,28 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);
>   */
>  int trace_seq_path(struct trace_seq *s, const struct path *path)
>  {
> -     unsigned char *p;
> +     unsigned int save_len = s->seq.len;
> +     int ret;
>  
>       if (s->full)
>               return 0;
>  
> +     __trace_seq_init(s);
> +
>       if (TRACE_SEQ_BUF_LEFT(s) < 1) {
>               s->full = 1;
>               return 0;
>       }
>  
> -     p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
> -     if (!IS_ERR(p)) {
> -             p = mangle_path(s->buffer + s->len, p, "\n");
> -             if (p) {
> -                     s->len = p - s->buffer;
> -                     return 1;
> -             }
> -     } else {
> -             s->buffer[s->len++] = '?';
> -             return 1;
> +     ret = seq_buf_path(&s->seq, path);

This returns zero on sucess.

> +     if (unlikely(seq_buf_has_overflowed(&s->seq))) {
> +             s->seq.len = save_len;
> +             s->full = 1;
> +             return 0;
>       }
>  
> -     s->full = 1;
> -     return 0;
> +     return ret;

and we want to return 1 on success =>

        return 1;

>  }
>  EXPORT_SYMBOL_GPL(trace_seq_path);

Best Regards,
Petr


PS: I have to leave for a bit now. I hope that I will be able to look
at the other patches later today.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to