22 Sep, 2020

1 commit


23 Apr, 2020

1 commit

  • Fix the following sparse warning:

    kernel/trace/tracing_map.c:286:6: warning: symbol
    'tracing_map_array_clear' was not declared. Should it be static?
    kernel/trace/tracing_map.c:297:6: warning: symbol
    'tracing_map_array_free' was not declared. Should it be static?
    kernel/trace/tracing_map.c:319:26: warning: symbol
    'tracing_map_array_alloc' was not declared. Should it be static?

    Link: http://lkml.kernel.org/r/20200410073312.38855-1-yanaijie@huawei.com

    Reported-by: Hulk Robot
    Signed-off-by: Jason Yan
    Signed-off-by: Steven Rostedt (VMware)

    Jason Yan
     

20 Dec, 2019

1 commit

  • The compare functions of the histogram code would be specific for the size
    of the value being compared (byte, short, int, long long). It would
    reference the value from the array via the type of the compare, but the
    value was stored in a 64 bit number. This is fine for little endian
    machines, but for big endian machines, it would end up comparing zeros or
    all ones (depending on the sign) for anything but 64 bit numbers.

    To fix this, first derference the value as a u64 then convert it to the type
    being compared.

    Link: http://lkml.kernel.org/r/20191211103557.7bed6928@gandalf.local.home

    Cc: stable@vger.kernel.org
    Fixes: 08d43a5fa063e ("tracing: Add lock-free tracing_map")
    Acked-by: Tom Zanussi
    Reported-by: Sven Schnelle
    Signed-off-by: Steven Rostedt (VMware)

    Steven Rostedt (VMware)
     

17 Aug, 2018

1 commit


13 Jun, 2018

1 commit

  • The vmalloc() function has no 2-factor argument form, so multiplication
    factors need to be wrapped in array_size(). This patch replaces cases of:

    vmalloc(a * b)

    with:
    vmalloc(array_size(a, b))

    as well as handling cases of:

    vmalloc(a * b * c)

    with:

    vmalloc(array3_size(a, b, c))

    This does, however, attempt to ignore constant size factors like:

    vmalloc(4 * 1024)

    though any constants defined via macros get caught up in the conversion.

    Any factors with a sizeof() of "unsigned char", "char", and "u8" were
    dropped, since they're redundant.

    The Coccinelle script used for this was:

    // Fix redundant parens around sizeof().
    @@
    type TYPE;
    expression THING, E;
    @@

    (
    vmalloc(
    - (sizeof(TYPE)) * E
    + sizeof(TYPE) * E
    , ...)
    |
    vmalloc(
    - (sizeof(THING)) * E
    + sizeof(THING) * E
    , ...)
    )

    // Drop single-byte sizes and redundant parens.
    @@
    expression COUNT;
    typedef u8;
    typedef __u8;
    @@

    (
    vmalloc(
    - sizeof(u8) * (COUNT)
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(__u8) * (COUNT)
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(char) * (COUNT)
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(unsigned char) * (COUNT)
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(u8) * COUNT
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(__u8) * COUNT
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(char) * COUNT
    + COUNT
    , ...)
    |
    vmalloc(
    - sizeof(unsigned char) * COUNT
    + COUNT
    , ...)
    )

    // 2-factor product with sizeof(type/expression) and identifier or constant.
    @@
    type TYPE;
    expression THING;
    identifier COUNT_ID;
    constant COUNT_CONST;
    @@

    (
    vmalloc(
    - sizeof(TYPE) * (COUNT_ID)
    + array_size(COUNT_ID, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * COUNT_ID
    + array_size(COUNT_ID, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * (COUNT_CONST)
    + array_size(COUNT_CONST, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * COUNT_CONST
    + array_size(COUNT_CONST, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * (COUNT_ID)
    + array_size(COUNT_ID, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * COUNT_ID
    + array_size(COUNT_ID, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * (COUNT_CONST)
    + array_size(COUNT_CONST, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * COUNT_CONST
    + array_size(COUNT_CONST, sizeof(THING))
    , ...)
    )

    // 2-factor product, only identifiers.
    @@
    identifier SIZE, COUNT;
    @@

    vmalloc(
    - SIZE * COUNT
    + array_size(COUNT, SIZE)
    , ...)

    // 3-factor product with 1 sizeof(type) or sizeof(expression), with
    // redundant parens removed.
    @@
    expression THING;
    identifier STRIDE, COUNT;
    type TYPE;
    @@

    (
    vmalloc(
    - sizeof(TYPE) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(TYPE))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * (COUNT) * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * (COUNT) * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * COUNT * (STRIDE)
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    |
    vmalloc(
    - sizeof(THING) * COUNT * STRIDE
    + array3_size(COUNT, STRIDE, sizeof(THING))
    , ...)
    )

    // 3-factor product with 2 sizeof(variable), with redundant parens removed.
    @@
    expression THING1, THING2;
    identifier COUNT;
    type TYPE1, TYPE2;
    @@

    (
    vmalloc(
    - sizeof(TYPE1) * sizeof(TYPE2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(TYPE2))
    , ...)
    |
    vmalloc(
    - sizeof(THING1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    vmalloc(
    - sizeof(THING1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(THING1), sizeof(THING2))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * COUNT
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    |
    vmalloc(
    - sizeof(TYPE1) * sizeof(THING2) * (COUNT)
    + array3_size(COUNT, sizeof(TYPE1), sizeof(THING2))
    , ...)
    )

    // 3-factor product, only identifiers, with redundant parens removed.
    @@
    identifier STRIDE, SIZE, COUNT;
    @@

    (
    vmalloc(
    - (COUNT) * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - COUNT * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - COUNT * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - (COUNT) * (STRIDE) * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - COUNT * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - (COUNT) * STRIDE * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - (COUNT) * (STRIDE) * (SIZE)
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    |
    vmalloc(
    - COUNT * STRIDE * SIZE
    + array3_size(COUNT, STRIDE, SIZE)
    , ...)
    )

    // Any remaining multi-factor products, first at least 3-factor products
    // when they're not all constants...
    @@
    expression E1, E2, E3;
    constant C1, C2, C3;
    @@

    (
    vmalloc(C1 * C2 * C3, ...)
    |
    vmalloc(
    - E1 * E2 * E3
    + array3_size(E1, E2, E3)
    , ...)
    )

    // And then all remaining 2 factors products when they're not all constants.
    @@
    expression E1, E2;
    constant C1, C2;
    @@

    (
    vmalloc(C1 * C2, ...)
    |
    vmalloc(
    - E1 * E2
    + array_size(E1, E2)
    , ...)
    )

    Signed-off-by: Kees Cook

    Kees Cook
     

11 Mar, 2018

3 commits

  • In order to allow information to be passed between trace events, add
    support for per-element variables to tracing_map. This provides a
    means for histograms to associate a value or values with an entry when
    it's saved or updated, and retrieved by a subsequent event occurrences.

    Variables can be set using tracing_map_set_var() and read using
    tracing_map_read_var(). tracing_map_var_set() returns true or false
    depending on whether or not the variable has been set or not, which is
    important for event-matching applications.

    tracing_map_read_var_once() reads the variable and resets it to the
    'unset' state, implementing read-once variables, which are also
    important for event-matching uses.

    Link: http://lkml.kernel.org/r/7fa001108252556f0c6dd9d63145eabfe3370d1a.1516069914.git.tom.zanussi@linux.intel.com

    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt (VMware)

    Tom Zanussi
     
  • We now have the logic to detect and remove duplicates in the
    tracing_map hash table. The code which merges duplicates in the
    histogram is redundant now. So, modify this code just to detect
    duplicates. The duplication detection code is still kept to ensure
    that any rare race condition which might cause duplicates does not go
    unnoticed.

    Link: http://lkml.kernel.org/r/55215cf59e2674391bdaf772fdafc4c393352b03.1516069914.git.tom.zanussi@linux.intel.com

    Signed-off-by: Vedang Patel
    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt (VMware)

    Vedang Patel
     
  • A duplicate in the tracing_map hash table is when 2 different entries
    have the same key and, as a result, the key_hash. This is possible due
    to a race condition in the algorithm. This race condition is inherent to
    the algorithm and not a bug. This was fine because, until now, we were
    only interested in the sum of all the values related to a particular
    key (the duplicates are dealt with in tracing_map_sort_entries()). But,
    with the inclusion of variables[1], we are interested in individual
    values. So, it will not be clear what value to choose when
    there are duplicates. So, the duplicates need to be removed.

    The duplicates can occur in the code in the following scenarios:

    - A thread is in the process of adding a new element. It has
    successfully executed cmpxchg() and inserted the key. But, it is still
    not done acquiring the trace_map_elt struct, populating it and storing
    the pointer to the struct in the value field of tracing_map hash table.
    If another thread comes in at this time and wants to add an element with
    the same key, it will not see the current element and add a new one.

    - There are multiple threads trying to execute cmpxchg at the same time,
    one of the threads will succeed and the others will fail. The ones which
    fail will go ahead increment 'idx' and add a new element there creating
    a duplicate.

    This patch detects and avoids the first condition by asking the thread
    which detects the duplicate to loop one more time. There is also a
    possibility of infinite loop if the thread which is trying to insert
    goes to sleep indefinitely and the one which is trying to insert a new
    element detects a duplicate. Which is why, the thread loops for
    map_size iterations before returning NULL.

    The second scenario is avoided by preventing the threads which failed
    cmpxchg() from incrementing idx. This way, they will loop
    around and check if the thread which succeeded in executing cmpxchg()
    had the same key.

    [1] http://lkml.kernel.org/r/cover.1498510759.git.tom.zanussi@linux.intel.com

    Link: http://lkml.kernel.org/r/e178e89ec399240331d383bd5913d649713110f4.1516069914.git.tom.zanussi@linux.intel.com

    Signed-off-by: Vedang Patel
    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt (VMware)

    Vedang Patel
     

05 Oct, 2017

1 commit

  • Lookups inflate the hitcount, making it essentially useless. Only
    inserts and updates should really affect the hitcount anyway, so
    explicitly filter lookups out.

    Link: http://lkml.kernel.org/r/c8d9dc39d269a8abf88bf4102d0dfc65deb0fc7f.1506105045.git.tom.zanussi@linux.intel.com

    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt (VMware)

    Tom Zanussi
     

24 Aug, 2017

1 commit

  • kmemleak reported the below leak when I was doing clear of the hist
    trigger. With this patch, the kmeamleak is gone.

    unreferenced object 0xffff94322b63d760 (size 32):
    comm "bash", pid 1522, jiffies 4403687962 (age 2442.311s)
    hex dump (first 32 bytes):
    00 01 00 00 04 00 00 00 08 00 00 00 ff 00 00 00 ................
    10 00 00 00 00 00 00 00 80 a8 7a f2 31 94 ff ff ..........z.1...
    backtrace:
    [] kmemleak_alloc+0x4a/0xa0
    [] kmem_cache_alloc_trace+0xca/0x1d0
    [] tracing_map_array_alloc+0x26/0x140
    [] kretprobe_trampoline+0x0/0x50
    [] create_hist_data+0x535/0x750
    [] event_hist_trigger_func+0x1f7/0x420
    [] event_trigger_write+0xfd/0x1a0
    [] __vfs_write+0x37/0x170
    [] vfs_write+0xb2/0x1b0
    [] SyS_write+0x55/0xc0
    [] do_syscall_64+0x67/0x150
    [] return_from_SYSCALL_64+0x0/0x6a
    [] 0xffffffffffffffff
    unreferenced object 0xffff9431f27aa880 (size 128):
    comm "bash", pid 1522, jiffies 4403687962 (age 2442.311s)
    hex dump (first 32 bytes):
    00 00 8c 2a 32 94 ff ff 00 f0 8b 2a 32 94 ff ff ...*2......*2...
    00 e0 8b 2a 32 94 ff ff 00 d0 8b 2a 32 94 ff ff ...*2......*2...
    backtrace:
    [] kmemleak_alloc+0x4a/0xa0
    [] __kmalloc+0xe8/0x220
    [] tracing_map_array_alloc+0xb1/0x140
    [] kretprobe_trampoline+0x0/0x50
    [] create_hist_data+0x535/0x750
    [] event_hist_trigger_func+0x1f7/0x420
    [] event_trigger_write+0xfd/0x1a0
    [] __vfs_write+0x37/0x170
    [] vfs_write+0xb2/0x1b0
    [] SyS_write+0x55/0xc0
    [] do_syscall_64+0x67/0x150
    [] return_from_SYSCALL_64+0x0/0x6a
    [] 0xffffffffffffffff

    Link: http://lkml.kernel.org/r/1502705898-27571-1-git-send-email-chuhu@redhat.com

    Cc: stable@vger.kernel.org
    Fixes: 08d43a5fa063 ("tracing: Add lock-free tracing_map")
    Signed-off-by: Chunyu Hu
    Signed-off-by: Steven Rostedt (VMware)

    Chunyu Hu
     

26 Apr, 2016

2 commits

  • If tracing_map_elt_alloc() fails, it will return ERR_PTR() instead of
    NULL, so change the check to IS_ERROR(). We also need to set the
    failed entry in the map->elts array to NULL instead of ERR_PTR() so
    tracing_map_free_elts() doesn't try freeing an ERR_PTR().

    tracing_map_free_elts() should also zero out what it frees so a
    reentrant call won't find previously freed elements.

    Link: http://lkml.kernel.org/r/f29d03b00bce3aac8cf151a8a30e6c83e5fee66d.1461610073.git.tom.zanussi@linux.intel.com

    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt

    Tom Zanussi
     
  • tracing_map_elt_alloc() returns ERR_PTRs on error, never NULL.

    Fixes: 08d43a5fa063 ('tracing: Add lock-free tracing_map')
    Link: http://lkml.kernel.org/r/20160423102347.GA11136@mwanda

    Acked-by: Tom Zanussi
    Signed-off-by: Dan Carpenter
    Signed-off-by: Steven Rostedt

    Dan Carpenter
     

20 Apr, 2016

2 commits

  • Make it clear exactly how many keys and values are supported through
    better defines, and add 1 to the vals count, since normally clients
    want support for at least a hitcount and two other values.

    Also, note the error return value for tracing_map_add_key/val_field()
    in the comments.

    Link: http://lkml.kernel.org/r/6696fa02ebc716aa344c27a571a2afaa25e5b4d4.1457029949.git.tom.zanussi@linux.intel.com

    Signed-off-by: Tom Zanussi
    Signed-off-by: Steven Rostedt

    Tom Zanussi
     
  • Add tracing_map, a special-purpose lock-free map for tracing.

    tracing_map is designed to aggregate or 'sum' one or more values
    associated with a specific object of type tracing_map_elt, which
    is associated by the map to a given key.

    It provides various hooks allowing per-tracer customization and is
    separated out into a separate file in order to allow it to be shared
    between multiple tracers, but isn't meant to be generally used outside
    of that context.

    The tracing_map implementation was inspired by lock-free map
    algorithms originated by Dr. Cliff Click:

    http://www.azulsystems.com/blog/cliff/2007-03-26-non-blocking-hashtable
    http://www.azulsystems.com/events/javaone_2007/2007_LockFreeHash.pdf

    Link: http://lkml.kernel.org/r/b43d68d1add33582a396f553c8ef705a33a6a748.1449767187.git.tom.zanussi@linux.intel.com

    Signed-off-by: Tom Zanussi
    Tested-by: Masami Hiramatsu
    Reviewed-by: Namhyung Kim
    Signed-off-by: Steven Rostedt

    Tom Zanussi