lkml.org 
[lkml]   [2021]   [Sep]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.10 037/236] s390/debug: keep debug data on resize
    Date
    From: Peter Oberparleiter <oberpar@linux.ibm.com>

    [ Upstream commit 1204777867e8486a88dbb4793fe256b31ea05eeb ]

    Any previously recorded s390dbf debug data is reset when a debug area
    is resized using the 'pages' sysfs attribute. This can make
    live-debugging unnecessarily complex.

    Fix this by copying existing debug data to the newly allocated debug
    area when resizing.

    Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com>
    Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    arch/s390/kernel/debug.c | 74 ++++++++++++++++++++++++++++------------
    1 file changed, 53 insertions(+), 21 deletions(-)

    diff --git a/arch/s390/kernel/debug.c b/arch/s390/kernel/debug.c
    index b6619ae9a3e0..e392d3e42b1d 100644
    --- a/arch/s390/kernel/debug.c
    +++ b/arch/s390/kernel/debug.c
    @@ -24,6 +24,7 @@
    #include <linux/export.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    +#include <linux/minmax.h>
    #include <linux/debugfs.h>

    #include <asm/debug.h>
    @@ -92,6 +93,8 @@ static int debug_hex_ascii_format_fn(debug_info_t *id, struct debug_view *view,
    char *out_buf, const char *in_buf);
    static int debug_sprintf_format_fn(debug_info_t *id, struct debug_view *view,
    char *out_buf, debug_sprintf_entry_t *curr_event);
    +static void debug_areas_swap(debug_info_t *a, debug_info_t *b);
    +static void debug_events_append(debug_info_t *dest, debug_info_t *src);

    /* globals */

    @@ -726,35 +729,28 @@ EXPORT_SYMBOL(debug_unregister);
    */
    static int debug_set_size(debug_info_t *id, int nr_areas, int pages_per_area)
    {
    - debug_entry_t ***new_areas;
    + debug_info_t *new_id;
    unsigned long flags;
    - int rc = 0;

    if (!id || (nr_areas <= 0) || (pages_per_area < 0))
    return -EINVAL;
    - if (pages_per_area > 0) {
    - new_areas = debug_areas_alloc(pages_per_area, nr_areas);
    - if (!new_areas) {
    - pr_info("Allocating memory for %i pages failed\n",
    - pages_per_area);
    - rc = -ENOMEM;
    - goto out;
    - }
    - } else {
    - new_areas = NULL;
    +
    + new_id = debug_info_alloc("", pages_per_area, nr_areas, id->buf_size,
    + id->level, ALL_AREAS);
    + if (!new_id) {
    + pr_info("Allocating memory for %i pages failed\n",
    + pages_per_area);
    + return -ENOMEM;
    }
    +
    spin_lock_irqsave(&id->lock, flags);
    - debug_areas_free(id);
    - id->areas = new_areas;
    - id->nr_areas = nr_areas;
    - id->pages_per_area = pages_per_area;
    - id->active_area = 0;
    - memset(id->active_entries, 0, sizeof(int)*id->nr_areas);
    - memset(id->active_pages, 0, sizeof(int)*id->nr_areas);
    + debug_events_append(new_id, id);
    + debug_areas_swap(new_id, id);
    + debug_info_free(new_id);
    spin_unlock_irqrestore(&id->lock, flags);
    pr_info("%s: set new size (%i pages)\n", id->name, pages_per_area);
    -out:
    - return rc;
    +
    + return 0;
    }

    /**
    @@ -821,6 +817,42 @@ static inline debug_entry_t *get_active_entry(debug_info_t *id)
    id->active_entries[id->active_area]);
    }

    +/* Swap debug areas of a and b. */
    +static void debug_areas_swap(debug_info_t *a, debug_info_t *b)
    +{
    + swap(a->nr_areas, b->nr_areas);
    + swap(a->pages_per_area, b->pages_per_area);
    + swap(a->areas, b->areas);
    + swap(a->active_area, b->active_area);
    + swap(a->active_pages, b->active_pages);
    + swap(a->active_entries, b->active_entries);
    +}
    +
    +/* Append all debug events in active area from source to destination log. */
    +static void debug_events_append(debug_info_t *dest, debug_info_t *src)
    +{
    + debug_entry_t *from, *to, *last;
    +
    + if (!src->areas || !dest->areas)
    + return;
    +
    + /* Loop over all entries in src, starting with oldest. */
    + from = get_active_entry(src);
    + last = from;
    + do {
    + if (from->clock != 0LL) {
    + to = get_active_entry(dest);
    + memset(to, 0, dest->entry_size);
    + memcpy(to, from, min(src->entry_size,
    + dest->entry_size));
    + proceed_active_entry(dest);
    + }
    +
    + proceed_active_entry(src);
    + from = get_active_entry(src);
    + } while (from != last);
    +}
    +
    /*
    * debug_finish_entry:
    * - set timestamp, caller address, cpu number etc.
    --
    2.30.2


    \
     
     \ /
      Last update: 2021-09-13 15:38    [W:7.659 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site