Re: [Crash-utility] [PATCH] Fix live debugging with lockdown=integrity
by lijiang
Thank you for the fix, Philipp. Applied:
https://github.com/crash-utility/crash/commit/01d20ca1861ffaf449c1c60aa05...
On Fri, Nov 12, 2021 at 1:03 AM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 11 Nov 2021 07:45:51 +0000
> From: HAGIO KAZUHITO(?????) <k-hagio-ab(a)nec.com>
> To: Philipp Rudo <prudo(a)redhat.com>
> Cc: "Discussion list for crash utility usage, maintenance and
> development" <crash-utility(a)redhat.com>
> Subject: Re: [Crash-utility] [PATCH] Fix live debugging with
> lockdown=integrity
> Message-ID:
> <
> TYYPR01MB67772F7C8616E337FF66787CDD949(a)TYYPR01MB6777.jpnprd01.prod.outlook.com
> >
>
> Content-Type: text/plain; charset="iso-2022-jp"
>
> -----Original Message-----
> > With kernel lockdown the access to kernel interfaces that allow to
> > extract confidential information (lockdown=confidentiality) or modify a
> > running kernel (lockdown=integrity) can be restricted. Two of the
> > interfaces that can be restricted are /dev/mem (integrity &
> > confidentiality) and /proc/kcore (confidentiality). With
> > lockdown=integrity this leads to a situation where /dev/mem exists but
> > is not readable while /proc/kcore exists and is readable. This breaks
> > crash's live debugging when it is invoked without argument, i.e.
> >
> > $ crash
> > [...]
> > crash: /dev/mem: Operation not permitted
> >
> > while passing /proc/kcore as image succeeds. The reason for this is that
> > crash always picks /dev/mem as source when it exits but doesn't check if
> > it is readable. Fix this by only selecting /dev/mem when it is readable.
> >
> > Signed-off-by: Philipp Rudo <prudo(a)redhat.com>
>
> Thank you for the patch.
>
> Acked-by: Kazuhito Hagio <k-hagio-ab(a)nec.com>
>
> Kazu
>
> > ---
> > filesys.c | 2 +-
> > main.c | 2 +-
> > 2 files changed, 2 insertions(+), 2 deletions(-)
> >
> > diff --git a/filesys.c b/filesys.c
> > index 3361b6c..43cbe82 100644
> > --- a/filesys.c
> > +++ b/filesys.c
> > @@ -3666,7 +3666,7 @@ get_live_memory_source(void)
> > if (pc->live_memsrc)
> > goto live_report;
> >
> > - if (file_exists("/dev/mem", NULL))
> > + if (file_readable("/dev/mem"))
> > pc->live_memsrc = "/dev/mem";
> > else if (file_exists("/proc/kcore", NULL)) {
> > pc->flags &= ~DEVMEM;
> > diff --git a/main.c b/main.c
> > index 71c59d2..b278c22 100644
> > --- a/main.c
> > +++ b/main.c
> > @@ -1119,7 +1119,7 @@ setup_environment(int argc, char **argv)
> > pc->flags2 |= REDZONE;
> > pc->confd = -2;
> > pc->machine_type = MACHINE_TYPE;
> > - if (file_exists("/dev/mem", NULL)) { /* defaults until argv[]
> is parsed */
> > + if (file_readable("/dev/mem")) { /* defaults until argv[] is
> parsed */
> > pc->readmem = read_dev_mem;
> > pc->writemem = write_dev_mem;
> > } else if (file_exists("/proc/kcore", NULL)) {
> > --
> > 2.31.1
>
3 years
Re: [Crash-utility] [PATCH] arm64 : Update the section_size_bits for latest kernel
by lijiang
On Thu, Nov 4, 2021 at 4:49 PM <crash-utility-request(a)redhat.com> wrote:
> Date: Thu, 4 Nov 2021 08:47:57 +0000
> From: HAGIO KAZUHITO(?????) <k-hagio-ab(a)nec.com>
> To: "er.ankurbansal(a)gmail.com" <er.ankurbansal(a)gmail.com>
> Cc: "Discussion list for crash utility usage, maintenance and
> development" <crash-utility(a)redhat.com>
> Subject: Re: [Crash-utility] [PATCH] arm64 : Update the
> section_size_bits for latest kernel
> Message-ID:
> <
> TYYPR01MB67775E90F3F2EF285ACF5E86DD8D9(a)TYYPR01MB6777.jpnprd01.prod.outlook.com
> >
>
> Content-Type: text/plain; charset="iso-2022-jp"
>
> Hi Ankur,
>
> Thanks for the patch.
>
> -----Original Message-----
> > correct the section_size_bits for kernel version >= 5.12
> > becuase of linux upstream change
> >
> https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commi...
> > 119a8ac8059416ec4
> > (arm64/sparsemem: reduce SECTION_SIZE_BITS)
> >
> > Change-Id: I31b66fbfe421a02aa9f370ce7a615fbc70efcf2f
> > ---
> > arm64.c | 10 ++++++++--
> > 1 file changed, 8 insertions(+), 2 deletions(-)
> >
> > diff --git a/arm64.c b/arm64.c
> > index 3dcbcc6..4a207fc 100644
> > --- a/arm64.c
> > +++ b/arm64.c
> > @@ -1123,9 +1123,15 @@ arm64_get_section_size_bits(void)
> > free(string);
> > } else if (kt->ikconfig_flags & IKCONFIG_AVAIL) {
> > if ((ret = get_kernel_config("CONFIG_MEMORY_HOTPLUG",
> NULL)) == IKCONFIG_Y) {
> > - if ((ret =
> get_kernel_config("CONFIG_HOTPLUG_SIZE_BITS", &string)) == IKCONFIG_STR)
> > + if (THIS_KERNEL_VERSION >= LINUX(5,12,0)){
> > + if((ret =
> get_kernel_config("CONFIG_ARM64_64K_PAGES", NULL)) == IKCONFIG_Y)
> > + machdep->section_size_bits = 29;
> > + else
> > + machdep->section_size_bits = 27;
> > + }
> > + else if ((ret =
> get_kernel_config("CONFIG_HOTPLUG_SIZE_BITS", &string)) ==
> > IKCONFIG_STR)
>
> Considering dumpfiles without vmcoreinfo and IKCONFIG too, it will be
> better
> to switch the default value of section_size_bits. We can use
> machdep->pagesize
> here, so how about this?
>
> - machdep->section_size_bits = _SECTION_SIZE_BITS;
> + if (THIS_KERNEL_VERSION >= LINUX(5,12,0)) {
> + if (machdep->pagesize == 65536)
> + machdep->section_size_bits = 29;
> + else
> + machdep->section_size_bits = 27;
> + } else
> + machdep->section_size_bits = _SECTION_SIZE_BITS;
>
>
This change covers more scenarios and looks good to me. Could you please
update this patch? Ankur and Kazu.
Thanks.
Lianbo
3 years
Re: [Crash-utility] [PATCH] Fix live debugging with lockdown=integrity
by lijiang
Hi, Philipp
Thank you for the fix.
Date: Tue, 9 Nov 2021 14:52:22 +0100
> From: Philipp Rudo <prudo(a)redhat.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH] Fix live debugging with
> lockdown=integrity
> Message-ID: <20211109135222.51636-1-prudo(a)redhat.com>
>
> With kernel lockdown the access to kernel interfaces that allow to
> extract confidential information (lockdown=confidentiality) or modify a
> running kernel (lockdown=integrity) can be restricted. Two of the
> interfaces that can be restricted are /dev/mem (integrity &
> confidentiality) and /proc/kcore (confidentiality). With
> lockdown=integrity this leads to a situation where /dev/mem exists but
> is not readable while /proc/kcore exists and is readable. This breaks
> crash's live debugging when it is invoked without argument, i.e.
>
> $ crash
> [...]
> crash: /dev/mem: Operation not permitted
>
> while passing /proc/kcore as image succeeds. The reason for this is that
> crash always picks /dev/mem as source when it exits but doesn't check if
> it is readable. Fix this by only selecting /dev/mem when it is readable.
>
> Signed-off-by: Philipp Rudo <prudo(a)redhat.com>
> ---
> filesys.c | 2 +-
> main.c | 2 +-
> 2 files changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/filesys.c b/filesys.c
> index 3361b6c..43cbe82 100644
> --- a/filesys.c
> +++ b/filesys.c
> @@ -3666,7 +3666,7 @@ get_live_memory_source(void)
> if (pc->live_memsrc)
> goto live_report;
>
> - if (file_exists("/dev/mem", NULL))
> + if (file_readable("/dev/mem"))
> pc->live_memsrc = "/dev/mem";
> else if (file_exists("/proc/kcore", NULL)) {
> pc->flags &= ~DEVMEM;
> diff --git a/main.c b/main.c
> index 71c59d2..b278c22 100644
> --- a/main.c
> +++ b/main.c
> @@ -1119,7 +1119,7 @@ setup_environment(int argc, char **argv)
> pc->flags2 |= REDZONE;
> pc->confd = -2;
> pc->machine_type = MACHINE_TYPE;
> - if (file_exists("/dev/mem", NULL)) { /* defaults until argv[]
> is parsed */
> + if (file_readable("/dev/mem")) { /* defaults until argv[] is
> parsed */
> pc->readmem = read_dev_mem;
> pc->writemem = write_dev_mem;
> } else if (file_exists("/proc/kcore", NULL)) {
> --
> 2.31.1
>
After applying this patch, it works, but redundant information is
displayed in the crash prompt as below. I marked it twice, is that expected?
[root@testvm crash]# ./crash
[69580.039885] Lockdown: crash: /dev/mem,kmem,port is restricted; see man
kernel_lockdown.7
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
crash 7.3.0++
Copyright (C) 2002-2021 Red Hat, Inc.
Copyright (C) 2004, 2005, 2006, 2010 IBM Corporation
Copyright (C) 1999-2006 Hewlett-Packard Co
Copyright (C) 2005, 2006, 2011, 2012 Fujitsu Limited
Copyright (C) 2006, 2007 VA Linux Systems Japan K.K.
Copyright (C) 2005, 2011, 2020-2021 NEC Corporation
Copyright (C) 1999, 2002, 2007 Silicon Graphics, Inc.
Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
Copyright (C) 2015, 2021 VMware, Inc.
This program is free software, covered by the GNU General Public License,
and you are welcome to change it and/or distribute copies of it under
certain conditions. Enter "help copying" to see the conditions.
This program has absolutely no warranty. Enter "help warranty" for details.
[69580.662388] Lockdown: crash: /dev/mem,kmem,port is restricted; see man
kernel_lockdown.7
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
GNU gdb (GDB) 10.2
...
crash>
Thanks.
Lianbo
3 years
[PATCH] Fix live debugging with lockdown=integrity
by Philipp Rudo
With kernel lockdown the access to kernel interfaces that allow to
extract confidential information (lockdown=confidentiality) or modify a
running kernel (lockdown=integrity) can be restricted. Two of the
interfaces that can be restricted are /dev/mem (integrity &
confidentiality) and /proc/kcore (confidentiality). With
lockdown=integrity this leads to a situation where /dev/mem exists but
is not readable while /proc/kcore exists and is readable. This breaks
crash's live debugging when it is invoked without argument, i.e.
$ crash
[...]
crash: /dev/mem: Operation not permitted
while passing /proc/kcore as image succeeds. The reason for this is that
crash always picks /dev/mem as source when it exits but doesn't check if
it is readable. Fix this by only selecting /dev/mem when it is readable.
Signed-off-by: Philipp Rudo <prudo(a)redhat.com>
---
filesys.c | 2 +-
main.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/filesys.c b/filesys.c
index 3361b6c..43cbe82 100644
--- a/filesys.c
+++ b/filesys.c
@@ -3666,7 +3666,7 @@ get_live_memory_source(void)
if (pc->live_memsrc)
goto live_report;
- if (file_exists("/dev/mem", NULL))
+ if (file_readable("/dev/mem"))
pc->live_memsrc = "/dev/mem";
else if (file_exists("/proc/kcore", NULL)) {
pc->flags &= ~DEVMEM;
diff --git a/main.c b/main.c
index 71c59d2..b278c22 100644
--- a/main.c
+++ b/main.c
@@ -1119,7 +1119,7 @@ setup_environment(int argc, char **argv)
pc->flags2 |= REDZONE;
pc->confd = -2;
pc->machine_type = MACHINE_TYPE;
- if (file_exists("/dev/mem", NULL)) { /* defaults until argv[] is parsed */
+ if (file_readable("/dev/mem")) { /* defaults until argv[] is parsed */
pc->readmem = read_dev_mem;
pc->writemem = write_dev_mem;
} else if (file_exists("/proc/kcore", NULL)) {
--
2.31.1
3 years
[ANNOUNCE] crash gcore command, version 1.6.0 is released
by d.hatayama@fujitsu.com
This is the release of crash gcore command, version 1.6.0.
This release includes the following 1 new feature and 2 bug fixes.
This is tested on the latest kernels on Fedora 33, RHEL8, RHEL7 and
RHEL6 on x86_64.
Note that ZRAM support is not included in this release because some
patch set is still needed in crash utility.
Hagio-san, could you update the description of crash gcore command
at https://crash-utility.github.io/extensions.html?
ChangeLog:
- NT_FILE note information is newly supported for tasks in both 64-bit
and 32-bit compatible mode:
# LANG=C eu-readelf -n core.1.systemd | awk '/FILE$/ {f=1} f == 1 {print $0}' | head -n 10
CORE 12957 FILE
240 files:
564b290de000-564b29112000 00000000 212992 /usr/lib/systemd/systemd
564b29112000-564b291de000 00104000 835584 /usr/lib/systemd/systemd
564b291de000-564b2923d000 00500000 389120 /usr/lib/systemd/systemd
564b2923d000-564b29282000 006d6000 282624 /usr/lib/systemd/systemd
564b29282000-564b29283000 0082f000 4096 /usr/lib/systemd/systemd
7ffbf12c2000-7ffbf134c000 00000000 565248 /etc/selinux/targeted/contexts/files/file_contexts.bin
7ffbf1352000-7ffbf135a000 00000000 32768 /usr/lib64/libnl-3.so.200.26.0
7ffbf135a000-7ffbf1369000 00028000 61440 /usr/lib64/libnl-3.so.200.26.0
(thirtsa.dreyfus(a)intel.com, d.hatayama(a)fujitsu.com)
- Fix failure of collecting vDSO mapping if compat vDSO is disabled
due to wrongly designed condition for compat tasks that tries to
determine vDSO mapping based on VDSO_HIGH_BASE. Without this patch,
vDSO mapping page is not collected for tasks running in 32-bit
compat mode and thus displaying backtrace by gdb's bt command for
the tasks could be incomplete.
(d.hatayama(a)fujitsu.com)
- Fix failure of invalid structure member offset with the message
"gcore: invalid structure member offset:
thread_struct_io_bitmap_max" due to change of kernel data structure
for io bitmap by the commit <577d5cd7e585> ("x86/ioperm: Move
iobitmap data into a struct").
(lijiang(a)redhat.com, d.hatayama(a)fujitsu.com)
MD5 CheckSum:
# md5sum crash-gcore-command-1.6.0.tar.gz
889843438ad702807d48cccfdee94e89 crash-gcore-command-1.6.0.tar.gz
--
Thanks.
HATAYAMA, Daisuke
3 years
Re: [Crash-utility] [PATCH] New sbitmap command
by lijiang
Hi, Sergey
Date: Mon, 4 Oct 2021 20:15:36 +0300
> From: Sergey Samoylenko <s.samoylenko(a)yadro.com>
> To: <crash-utility(a)redhat.com>
> Cc: Sergey Samoylenko <s.samoylenko(a)yadro.com>, linux(a)yadro.com
> Subject: [Crash-utility] [PATCH] New sbitmap command
> Message-ID: <20211004171536.30971-1-s.samoylenko(a)yadro.com>
> Content-Type: text/plain
>
> Patch adds new 'sbitmap' command. This command dumps
> the contents of the sbitmap_queue structure and the used
> bits in the bitmap. Also, it shows the dump of a structure
> array associated with the sbitmap_queue.
>
> Signed-off-by: Sergey Samoylenko <s.samoylenko(a)yadro.com>
> ---
> Makefile | 7 +-
> defs.h | 2 +
> global_data.c | 1 +
> help.c | 89 ++++++++
> sbitmap.c | 591 ++++++++++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 688 insertions(+), 2 deletions(-)
> create mode 100644 sbitmap.c
>
> diff --git a/Makefile b/Makefile
> index ece1306..c116177 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -72,7 +72,7 @@ CFILES=main.c tools.c global_data.c memory.c filesys.c
> help.c task.c \
> xen_hyper.c xen_hyper_command.c xen_hyper_global_data.c \
> xen_hyper_dump_tables.c kvmdump.c qemu.c qemu-load.c sadump.c
> ipcs.c \
> ramdump.c vmware_vmss.c vmware_guestdump.c \
> - xen_dom0.c kaslr_helper.c
> + xen_dom0.c kaslr_helper.c sbitmap.c
>
> SOURCE_FILES=${CFILES} ${GENERIC_HFILES} ${MCORE_HFILES} \
> ${REDHAT_CFILES} ${REDHAT_HFILES} ${UNWIND_HFILES} \
> @@ -92,7 +92,7 @@ OBJECT_FILES=main.o tools.o global_data.o memory.o
> filesys.o help.o task.o \
> xen_hyper.o xen_hyper_command.o xen_hyper_global_data.o \
> xen_hyper_dump_tables.o kvmdump.o qemu.o qemu-load.o sadump.o
> ipcs.o \
> ramdump.o vmware_vmss.o vmware_guestdump.o \
> - xen_dom0.o kaslr_helper.o
> + xen_dom0.o kaslr_helper.o sbitmap.o
>
> MEMORY_DRIVER_FILES=memory_driver/Makefile memory_driver/crash.c
> memory_driver/README
>
> @@ -346,6 +346,9 @@ cmdline.o: ${GENERIC_HFILES} cmdline.c
> tools.o: ${GENERIC_HFILES} tools.c
> ${CC} -c ${CRASH_CFLAGS} tools.c ${WARNING_OPTIONS}
> ${WARNING_ERROR}
>
> +sbitmap.o: ${GENERIC_HFILES} sbitmap.c
> + ${CC} -c ${CRASH_CFLAGS} sbitmap.c ${WARNING_OPTIONS}
> ${WARNING_ERROR}
> +
> global_data.o: ${GENERIC_HFILES} global_data.c
> ${CC} -c ${CRASH_CFLAGS} global_data.c ${WARNING_OPTIONS}
> ${WARNING_ERROR}
>
> diff --git a/defs.h b/defs.h
> index eb1c71b..1fa5c21 100644
> --- a/defs.h
> +++ b/defs.h
> @@ -4956,6 +4956,7 @@ void cmd_mach(void); /* main.c */
> void cmd_help(void); /* help.c */
> void cmd_test(void); /* test.c */
> void cmd_ascii(void); /* tools.c */
> +void cmd_sbitmap(void); /* sbitmap.c */
> void cmd_bpf(void); /* bfp.c */
> void cmd_set(void); /* tools.c */
> void cmd_eval(void); /* tools.c */
> @@ -5543,6 +5544,7 @@ void display_help_screen(char *);
> extern char *help_pointer[];
> extern char *help_alias[];
> extern char *help_ascii[];
> +extern char *help_sbitmap[];
> extern char *help_bpf[];
> extern char *help_bt[];
> extern char *help_btop[];
> diff --git a/global_data.c b/global_data.c
> index a316d1c..55524e3 100644
> --- a/global_data.c
> +++ b/global_data.c
> @@ -105,6 +105,7 @@ struct command_table_entry linux_command_table[] = {
> {"rd", cmd_rd, help_rd, MINIMAL},
> {"repeat", cmd_repeat, help_repeat, 0},
> {"runq", cmd_runq, help_runq, REFRESH_TASK_TABLE},
> + {"sbitmap", cmd_sbitmap, help_sbitmap, 0},
> {"search", cmd_search, help_search, 0},
> {"set", cmd_set, help_set, REFRESH_TASK_TABLE |
> MINIMAL},
> {"sig", cmd_sig, help_sig, REFRESH_TASK_TABLE},
> diff --git a/help.c b/help.c
> index 6c262a3..b946745 100644
> --- a/help.c
> +++ b/help.c
> @@ -967,6 +967,95 @@ char *help_ascii[] = {
> NULL
> };
>
> +char *help_sbitmap[] = {
> +"sbitmap",
> +"sbitmap_queue struct contents",
> +"[-s struct[.member[,member]] -p address [-v]] address",
> +" This command dumps the contents of the sbitmap_queue structure and",
> +" the used bits in the bitmap. Also, it shows the dump of a structure",
> +" array associated with the sbitmap_queue.",
> +"",
> +" The arguments are as follows:",
> +"",
> +" -s struct - name of a C-code structure, that is stored in an array",
> +" sssociated with sbitmap_queue structure. Use the",
> +" \"struct.member\" format in order to display a
> particular",
> +" member of the structure. -s option requires -p option",
> +"",
> +" -p address - address of a structure array associated with
> sbitmap_queue",
> +" structure. The set bits in sbitmap are used for the
> index",
> +" in an associated array.",
> +"",
> +" -x - override default output format with hexadecimal format.",
> +"",
> +" -d - override default output format with decimal format.",
> +"",
> +" -v - By default, the sbitmap command shows only a used
> sbitmap",
> +" index and a structure address in the associated array.",
> +" This flag says to print of a formatted display of the",
> +" contents of a structure in an associated array. -v
> option",
> +" requires of -s.",
> +"",
> +"EXAMPLES",
> +"",
> +" Display the common sbitmap information:",
> +"",
> +" %s> sbitmap ffffffffc06b9420",
> +" depth = 256",
> +" busy = 15",
> +" cleared = 1",
> +" bits_per_word = 64",
> +" map_nr = 4",
> +" alloc_hint = {193, 78}",
> +" wake_batch = 8",
> +" wake_index = 0",
> +" ws_active = 0",
> +" ws = {",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" { .wait_cnt = 8, .wait = inactive },",
> +" }",
> +" round_robin = 0",
> +" min_shallow_depth = 4294967295",
> +"",
> +" 00000000: 0000 0000 0000 0000 ffbf 0000 0000 0000",
> +" 00000010: 0000 0000 0000 0000 0000 0000 0000 0000",
> +"",
> +" Display the structure address is associated with sbitmap_queue:",
> +"",
>
Other changes look good to me. But I didn't see the relationship between
test_data and sbitmap_queue according to the example.
Could you please describe more details about what's the
structure associated with sbitmap_queue? Thanks.
> +" %s> sbitmap -s test_data -p ffff973422dac000 ffffffffc06b9420",
> +" 64: 0xffff973422dac200",
> +" 65: 0xffff973422dac208",
> +" 66: 0xffff973422dac210",
> +" ...",
> +"",
> +" Display a formatted content of a structures:",
> +"",
> +" %s> sbitmap -s test_data -p ffff973422dac000 -v ffffffffc06b9420",
> +" 64 (0xffff973422dac200):",
> +" struct test_data {",
> +" tag = 64,",
> +" cpu = 1",
> +" }",
> +" 65 (0xffff973422dac208):",
> +" struct test_data {",
> +" tag = 65,",
> +" cpu = 1",
> +" }",
> +" 66 (0xffff973422dac210):",
> +" struct test_data {",
> +" tag = 66,",
> +" cpu = 1",
> +" }",
> +" ...",
> +NULL
> +};
> +
> char *help_quit[] = {
> "quit",
> "exit this session",
> diff --git a/sbitmap.c b/sbitmap.c
> new file mode 100644
> index 0000000..71522f8
> --- /dev/null
> +++ b/sbitmap.c
> @@ -0,0 +1,591 @@
> +/* sbitmap.c - core analysis suite
> + *
> + * Copyright (C) 1999, 2000, 2001, 2002 Mission Critical Linux, Inc.
> + * Copyright (C) 2002-2020 David Anderson
> + * Copyright (C) 2002-2020 Red Hat, Inc. All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include "defs.h"
> +#include <stdbool.h>
> +
> +#define SBQ_WAIT_QUEUES 8
> +
> +static inline unsigned int __const_hweight8(unsigned long w)
> +{
> + return
> + (!!((w) & (1ULL << 0))) +
> + (!!((w) & (1ULL << 1))) +
> + (!!((w) & (1ULL << 2))) +
> + (!!((w) & (1ULL << 3))) +
> + (!!((w) & (1ULL << 4))) +
> + (!!((w) & (1ULL << 5))) +
> + (!!((w) & (1ULL << 6))) +
> + (!!((w) & (1ULL << 7)));
> +}
> +
> +#define __const_hweight16(w) (__const_hweight8(w) +
> __const_hweight8((w) >> 8))
> +#define __const_hweight32(w) (__const_hweight16(w) +
> __const_hweight16((w) >> 16))
> +#define __const_hweight64(w) (__const_hweight32(w) +
> __const_hweight32((w) >> 32))
> +
> +#define hweight32(w) __const_hweight32(w)
> +#define hweight64(w) __const_hweight64(w)
> +
> +#define BIT(nr) (1UL << (nr))
> +
> +/* sbitmap and sbitmap_word structs context */
> +struct sbitmap_context {
> + unsigned sb_depth;
> + unsigned sb_shift;
> + unsigned sb_map_nr;
> + ulong sb_map_addr;
> + unsigned sb_map_size;
> +
> + int w_depth_off;
> + int w_word_off;
> + int w_cleared_off;
> +};
> +
> +/* sbitmap_queue struct context */
> +struct sbitmap_queue_context {
> + ulong sb_addr;
> + ulong alloc_hint;
> + unsigned int wake_batch;
> + int wake_index;
> + ulong ws_addr;
> + int ws_active;
> + bool round_robin;
> + unsigned int min_shallow_depth;
> +
> +};
> +
> +struct sbitmap_data {
> +#define SD_FLAG_STRUCT_NAME (VERBOSE << 1)
> +#define SD_FLAG_STRUCT_ADDR (VERBOSE << 2)
> +#define SD_FLAG_STRUCT_MEMBER (VERBOSE << 3)
> + ulong flags;
> + int radix;
> + /* sbitmap_queue info */
> + ulong addr;
> + /* data array info */
> + char *data_name;
> + ulong data_addr;
> +
> + struct sbitmap_queue_context sqc;
> + struct sbitmap_context sc;
> +};
> +
> +static inline unsigned long min(unsigned long a, unsigned long b)
> +{
> + return (a < b) ? a : b;
> +}
> +
> +static void __readmem(ulong addr, void *buffer, size_t size)
> +{
> + ulong flag = FAULT_ON_ERROR;
> +
> + if (!readmem(addr, KVADDR, buffer, size, "__readmem", flag))
> + error(FATAL, "failed read memory: 0x%x\n", addr);
> +}
> +
> +static ulong __read_ulong(ulong addr)
> +{
> + ulong value;
> +
> + __readmem(addr, &value, sizeof(value));
> + return value;
> +}
> +
> +static long __struct_size(char *name)
> +{
> + long size;
> +
> + size = STRUCT_SIZE(name);
> + if (size < 0)
> + error(FATAL, "Invalid struct size: %s\n", name);
> +
> + return size;
> +}
> +
> +static long __member_offset(char *name, char *member)
> +{
> + long offset;
> +
> + offset = MEMBER_OFFSET(name, member);
> + if (offset == INVALID_OFFSET)
> + offset = ANON_MEMBER_OFFSET(name, member);
> + if (offset == INVALID_OFFSET)
> + error(FATAL, "Can't get offset of '%s.%s'\n", name,
> member);
> +
> + return offset;
> +}
> +
> +static unsigned long __last_word_mask(unsigned long nbits)
> +{
> + return ~0UL >> (-(nbits) & (BITS_PER_LONG - 1));
> +}
> +
> +static unsigned long bitmap_hweight_long(unsigned long w)
> +{
> + return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
> +}
> +
> +static unsigned long bitmap_weight(unsigned long bitmap, unsigned int
> bits)
> +{
> + unsigned long w = 0;
> +
> + w += bitmap_hweight_long(bitmap);
> + if (bits % BITS_PER_LONG)
> + w += bitmap_hweight_long(bitmap & __last_word_mask(bits));
> +
> + return w;
> +}
> +
> +static unsigned int __sbitmap_weight(const struct sbitmap_context *sc,
> bool set)
> +{
> + unsigned int weight = 0;
> + ulong addr = sc->sb_map_addr;
> + unsigned long depth, word, cleared;
> + int i;
> +
> + for (i = 0; i < sc->sb_map_nr; i++) {
> + depth = __read_ulong(addr + sc->w_depth_off);
> +
> + if (set) {
> + word = __read_ulong(addr + sc->w_word_off);
> + weight += bitmap_weight(word, depth);
> + } else {
> + cleared = __read_ulong(addr + sc->w_cleared_off);
> + weight += bitmap_weight(cleared, depth);
> + }
> +
> + addr += sc->sb_map_size;
> + }
> +
> + return weight;
> +}
> +
> +static unsigned int sbitmap_weight(const struct sbitmap_context *sc)
> +{
> + return __sbitmap_weight(sc, true);
> +}
> +
> +static unsigned int sbitmap_cleared(const struct sbitmap_context *sc)
> +{
> + return __sbitmap_weight(sc, false);
> +}
> +
> +static void sbitmap_queue_show(const struct sbitmap_queue_context *sqc,
> + const struct sbitmap_context *sc)
> +{
> + int cpus = get_cpus_possible();
> + int sbq_wait_state_size, wait_cnt_off, wait_off, list_head_off;
> + bool first;
> + int i;
> +
> + fprintf(fp, "depth = %u\n", sc->sb_depth);
> + fprintf(fp, "busy = %u\n", sbitmap_weight(sc) -
> sbitmap_cleared(sc));
> + fprintf(fp, "cleared = %u\n", sbitmap_cleared(sc));
> + fprintf(fp, "bits_per_word = %u\n", 1U << sc->sb_shift);
> + fprintf(fp, "map_nr = %u\n", sc->sb_map_nr);
> +
> + fputs("alloc_hint = {", fp);
> + first = true;
> + for (i = 0; i < cpus; i++) {
> + if (!first)
> + fprintf(fp, ", ");
> + first = false;
> +
> + ulong ptr = kt->__per_cpu_offset[i] + sqc->alloc_hint;
> + fprintf(fp, "%lu", __read_ulong(ptr));
> + }
> + fputs("}\n", fp);
> +
> + fprintf(fp, "wake_batch = %u\n", sqc->wake_batch);
> + fprintf(fp, "wake_index = %d\n", sqc->wake_index);
> + fprintf(fp, "ws_active = %d\n", sqc->ws_active);
> +
> + sbq_wait_state_size = __struct_size("sbq_wait_state");
> + wait_cnt_off = __member_offset("sbq_wait_state", "wait_cnt");
> + wait_off = __member_offset("sbq_wait_state", "wait");
> + list_head_off = __member_offset("wait_queue_head", "head");
> +
> + fputs("ws = {\n", fp);
> + for (i = 0; i < SBQ_WAIT_QUEUES; i++) {
> + ulong ws_addr = sqc->ws_addr + (sbq_wait_state_size * i);
> + struct kernel_list_head lh;
> + ulong wait_cnt_addr, list_head_addr;
> + ulong wait_cnt;
> +
> + wait_cnt_addr = ws_addr + wait_cnt_off;
> + __readmem(wait_cnt_addr, &wait_cnt, sizeof(wait_cnt));
> +
> + list_head_addr = ws_addr + wait_off + list_head_off;
> + __readmem(list_head_addr, &lh, sizeof(lh));
> +
> + fprintf(fp, "\t{ .wait_cnt = %lu, .wait = %s },\n",
> + wait_cnt, (lh.next == lh.prev) ? "inactive" :
> "active");
> + }
> + fputs("}\n", fp);
> +
> + fprintf(fp, "round_robin = %d\n", sqc->round_robin);
> + fprintf(fp, "min_shallow_depth = %u\n", sqc->min_shallow_depth);
> +}
> +
> +static void sbitmap_emit_byte(unsigned int offset, uint8_t byte)
> +{
> + if ((offset &0xf) == 0) {
> + if (offset != 0)
> + fputc('\n', fp);
> + fprintf(fp, "%08x:", offset);
> + }
> + if ((offset & 0x1) == 0)
> + fputc(' ', fp);
> + fprintf(fp, "%02x", byte);
> +}
> +
> +static void sbitmap_bitmap_show(const struct sbitmap_context *sc)
> +{
> + uint8_t byte = 0;
> + unsigned int byte_bits = 0;
> + unsigned int offset = 0;
> + int i;
> +
> + for (i = 0; i < sc->sb_map_nr; i++) {
> + ulong addr = sc->sb_map_addr + (sc->sb_map_size * i);
> + unsigned long word = __read_ulong(addr + sc->w_word_off);
> + unsigned long cleared = __read_ulong(addr +
> sc->w_cleared_off);
> + unsigned long word_bits = __read_ulong(addr +
> sc->w_depth_off);
> +
> + word &= ~cleared;
> +
> + while (word_bits > 0) {
> + unsigned int bits = min(8 - byte_bits, word_bits);
> +
> + byte |= (word & (BIT(bits) - 1)) << byte_bits;
> + byte_bits += bits;
> + if (byte_bits == 8) {
> + sbitmap_emit_byte(offset, byte);
> + byte = 0;
> + byte_bits = 0;
> + offset++;
> + }
> + word >>= bits;
> + word_bits -= bits;
> + }
> +
> + }
> + if (byte_bits) {
> + sbitmap_emit_byte(offset, byte);
> + offset++;
> + }
> + if (offset)
> + fputc('\n', fp);
> +}
> +
> +static void sbitmap_queue_dump(const struct sbitmap_data *sd)
> +{
> + sbitmap_queue_show(&sd->sqc, &sd->sc);
> + fputc('\n', fp);
> + sbitmap_bitmap_show(&sd->sc);
> +}
> +
> +static unsigned long sbitmap_find_next_bit(unsigned long word,
> + unsigned long size, unsigned long offset)
> +{
> + if (size > BITS_PER_LONG)
> + error(FATAL, "%s: word size isn't correct\n", __func__);
> +
> + for (; offset < size; offset++)
> + if (word & (1UL << offset))
> + return offset;
> +
> + return size;
> +}
> +
> +typedef bool (*sb_for_each_fn)(unsigned int, void *);
> +
> +static void __sbitmap_for_each_set(const struct sbitmap_context *sc,
> + unsigned int start, sb_for_each_fn fn, void *data)
> +{
> + unsigned int index;
> + unsigned int nr;
> + unsigned int scanned = 0;
> +
> + if (start >= sc->sb_map_nr)
> + start = 0;
> +
> + index = start >> sc->sb_shift;
> + nr = start & ((1U << sc->sb_shift) - 1U);
> +
> + while (scanned < sc->sb_depth) {
> + unsigned long w_addr = sc->sb_map_addr + (sc->sb_map_size
> * index);
> +
> + unsigned long w_depth = __read_ulong(w_addr +
> sc->w_depth_off);
> + unsigned long w_word = __read_ulong(w_addr +
> sc->w_word_off);
> + unsigned long w_cleared = __read_ulong(w_addr +
> sc->w_cleared_off);
> +
> + unsigned long word;
> + unsigned int depth = min(w_depth - nr, sc->sb_depth -
> scanned);
> +
> + scanned += depth;
> + word = w_word & ~w_cleared;
> + if (!word)
> + goto next;
> +
> + /*
> + * On the first iteration of the outer loop, we need to
> add the
> + * bit offset back to the size of the word for
> find_next_bit().
> + * On all other iterations, nr is zero, so this is a noop.
> + */
> + depth += nr;
> + while (1) {
> + nr = sbitmap_find_next_bit(word, depth, nr);
> + if (nr >= depth)
> + break;
> + if (!fn((index << sc->sb_shift) + nr, data))
> + return;
> +
> + nr++;
> + }
> +next:
> + nr = 0;
> + if (++index >= sc->sb_map_nr)
> + index = 0;
> + }
> +}
> +
> +static void sbitmap_for_each_set(const struct sbitmap_context *sc,
> + sb_for_each_fn fn, void *data)
> +{
> + __sbitmap_for_each_set(sc, 0, fn, data);
> +}
> +
> +static void sbitmap_dump_struct_members(const char *s, ulong addr,
> unsigned radix)
> +{
> + int i, argc;
> + char *p1, *p2;
> + char *structname, *members;
> + char *arglist[MAXARGS];
> +
> + structname = GETBUF(strlen(s) + 1);
> + members = GETBUF(strlen(s) + 1);
> +
> + strcpy(structname, s);
> + p1 = strstr(structname, ".") + 1;
> +
> + p2 = strstr(s, ".") + 1;
> + strcpy(members, p2);
> + replace_string(members, ",", ' ');
> + argc = parse_line(members, arglist);
> +
> + for (i = 0; i < argc; i++) {
> + *p1 = NULLCHAR;
> + strcat(structname, arglist[i]);
> + dump_struct_member(structname, addr, radix);
> + }
> +
> + FREEBUF(structname);
> + FREEBUF(members);
> +}
> +
> +struct data_info {
> + ulong addr;
> + int size;
> + char *name;
> + unsigned radix;
> + bool verbose;
> + bool members;
> +};
> +
> +static bool sbitmap_data_print(unsigned int idx, void *data)
> +{
> + const struct data_info *d = data;
> + ulong addr = d->addr + (d->size * idx);
> +
> + if (d->verbose) {
> + fprintf(fp, "%d (0x%08lx):\n", idx, addr);
> + if (d->members)
> + sbitmap_dump_struct_members(d->name, addr,
> d->radix);
> + else
> + dump_struct(d->name, addr, d->radix);
> + } else
> + fprintf(fp, "%d: 0x%08lx\n", idx, addr);
> +
> + return true;
> +}
> +
> +static char *__get_struct_name(const char *s)
> +{
> + char *name, *p;
> +
> + name = GETBUF(strlen(s) + 1);
> + strcpy(name, s);
> +
> + p = strstr(name, ".");
> + *p = NULLCHAR;
> +
> + return name;
> +}
> +
> +static void sbitmap_data_dump(const struct sbitmap_data *sd)
> +{
> + struct data_info d = {0};
> +
> + d.addr = sd->data_addr;
> + d.name = sd->data_name;
> + d.radix = sd->radix;
> + d.verbose = !!(sd->flags & VERBOSE);
> + d.members = !!(sd->flags & SD_FLAG_STRUCT_MEMBER);
> +
> + if (d.members) {
> + char *name = __get_struct_name(d.name);
> + d.size = __struct_size(name);
> + FREEBUF(name);
> + } else
> + d.size = __struct_size(d.name);
> +
> + sbitmap_for_each_set(&sd->sc, sbitmap_data_print, &d);
> +}
> +
> +static void load_sbitmap_queue_context(ulong addr, struct
> sbitmap_queue_context *sqc)
> +{
> + char *sb_q = "sbitmap_queue";
> +
> + sqc->sb_addr = addr + __member_offset(sb_q, "sb");
> + __readmem(addr + __member_offset(sb_q, "alloc_hint"),
> &sqc->alloc_hint, sizeof(sqc->alloc_hint));
> + __readmem(addr + __member_offset(sb_q, "wake_batch"),
> &sqc->wake_batch, sizeof(sqc->wake_batch));
> + __readmem(addr + __member_offset(sb_q, "wake_index"),
> &sqc->wake_index, sizeof(sqc->wake_index));
> + __readmem(addr + __member_offset(sb_q, "ws"), &sqc->ws_addr,
> sizeof(sqc->ws_addr));
> + __readmem(addr + __member_offset(sb_q, "ws_active"),
> &sqc->ws_active, sizeof(sqc->ws_active));
> + __readmem(addr + __member_offset(sb_q, "round_robin"),
> &sqc->round_robin, sizeof(sqc->round_robin));
> + __readmem(addr + __member_offset(sb_q, "min_shallow_depth"),
> &sqc->min_shallow_depth, sizeof(sqc->min_shallow_depth));
> +}
> +
> +static void load_sbitmap_context(ulong addr, struct sbitmap_context *sc)
> +{
> + char *sb = "sbitmap";
> + char *map = "sbitmap_word";
> +
> + __readmem(addr + __member_offset(sb, "depth"), &sc->sb_depth,
> sizeof(sc->sb_depth));
> + __readmem(addr + __member_offset(sb, "shift"), &sc->sb_shift,
> sizeof(sc->sb_shift));
> + __readmem(addr + __member_offset(sb, "map_nr"), &sc->sb_map_nr,
> sizeof(sc->sb_map_nr));
> + __readmem(addr + __member_offset(sb, "map"), &sc->sb_map_addr,
> sizeof(sc->sb_map_addr));
> + sc->sb_map_size = __struct_size(map);
> + sc->w_depth_off = __member_offset(map, "depth");
> + sc->w_word_off = __member_offset(map, "word");
> + sc->w_cleared_off = __member_offset(map, "cleared");
> +}
> +
> +void cmd_sbitmap(void)
> +{
> + struct sbitmap_data sd = {0};
> + int c;
> +
> + while ((c = getopt(argcnt, args, "s:p:xdv")) != EOF) {
> + switch (c) {
> + case 's':
> + if (sd.flags & SD_FLAG_STRUCT_NAME)
> + error(FATAL, "-s option (%s) already
> entered\n", sd.data_name);
> +
> + sd.data_name = optarg;
> + sd.flags |= SD_FLAG_STRUCT_NAME;
> +
> + break;
> +
> + case 'p':
> + if (sd.flags & SD_FLAG_STRUCT_ADDR)
> + error(FATAL, "-m option (0x%lx) already
> entered\n", sd.data_addr);
>
^^
The "-m" should be the "-p" option,right?
Thanks.
Lianbo
+ else if (!IS_A_NUMBER(optarg))
> + error(FATAL, "invalid -m option: %s\n",
> optarg);
>
Ditto.
> +
> + sd.data_addr = htol(optarg, FAULT_ON_ERROR, NULL);
> + if (!IS_KVADDR(sd.data_addr))
> + error(FATAL, "invalid kernel virtual
> address: %s\n", optarg);
> + sd.flags |= SD_FLAG_STRUCT_ADDR;
> +
> + break;
> +
> + case 'v':
> + sd.flags |= VERBOSE;
> + break;
> +
> + case 'x':
> + if (sd.radix == 10)
> + error(FATAL, "-d and -x are mutually
> exclusive\n");
> + sd.radix = 16;
> + break;
> +
> + case 'd':
> + if (sd.radix == 16)
> + error(FATAL, "-d and -x are mutually
> exclusive\n");
> + sd.radix = 10;
> + break;
> +
> + default:
> + argerrs++;
> + break;
> + }
> + }
> +
> + if (argerrs)
> + cmd_usage(pc->curcmd, SYNOPSIS);
> +
> + if (!args[optind]) {
> + error(INFO, "command argument is required\n");
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + } else if (args[optind] && args[optind + 1]) {
> + error(INFO, "too many arguments\n");
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + } else if (!IS_A_NUMBER(args[optind])) {
> + error(FATAL, "invalid command argument: %s\n",
> args[optind]);
> + }
> +
> + sd.addr = htol(args[optind], FAULT_ON_ERROR, NULL);
> + if (!IS_KVADDR(sd.addr))
> + error(FATAL, "invalid kernel virtual address: %s\n",
> args[optind]);
> +
> + if ((sd.flags & SD_FLAG_STRUCT_NAME) && !(sd.flags &
> SD_FLAG_STRUCT_ADDR)) {
> + error(INFO, "-s option requires -m option");
>
Ditto.
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + } else if ((sd.flags & SD_FLAG_STRUCT_ADDR) && !(sd.flags &
> SD_FLAG_STRUCT_NAME)) {
> + error(FATAL, "-m option is used with -s option only\n");
>
Ditto.
> + cmd_usage(pc->curcmd, SYNOPSIS);
> + }
> +
> + if (sd.flags & SD_FLAG_STRUCT_NAME) {
> + bool error_flag = false;
> +
> + if (count_chars(sd.data_name, '.') > 0)
> + sd.flags |= SD_FLAG_STRUCT_MEMBER;
> +
> + if (sd.flags & SD_FLAG_STRUCT_MEMBER) {
> + char *data_name = __get_struct_name(sd.data_name);
> + if (!STRUCT_EXISTS(data_name))
> + error_flag = true;
> + FREEBUF(data_name);
> + } else {
> + if (!STRUCT_EXISTS(sd.data_name))
> + error_flag = true;
> + }
> + if (error_flag)
> + error(FATAL, "invalid data structure reference:
> %s\n", sd.data_name);
> + }
> +
> + load_sbitmap_queue_context(sd.addr, &sd.sqc);
> + load_sbitmap_context(sd.sqc.sb_addr, &sd.sc);
> +
> + if (sd.flags & SD_FLAG_STRUCT_NAME)
> + sbitmap_data_dump(&sd);
> + else
> + sbitmap_queue_dump(&sd);
> +}
> --
> 2.25.1
>
>
3 years
[PATCH] arm64 : Update the section_size_bits for latest kernel
by Ankur Bansal
correct the section_size_bits for kernel version >= 5.12
becuase of linux upstream change
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commi...
(arm64/sparsemem: reduce SECTION_SIZE_BITS)
Change-Id: I31b66fbfe421a02aa9f370ce7a615fbc70efcf2f
---
arm64.c | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/arm64.c b/arm64.c
index 3dcbcc6..4a207fc 100644
--- a/arm64.c
+++ b/arm64.c
@@ -1123,9 +1123,15 @@ arm64_get_section_size_bits(void)
free(string);
} else if (kt->ikconfig_flags & IKCONFIG_AVAIL) {
if ((ret = get_kernel_config("CONFIG_MEMORY_HOTPLUG", NULL)) == IKCONFIG_Y) {
- if ((ret = get_kernel_config("CONFIG_HOTPLUG_SIZE_BITS", &string)) == IKCONFIG_STR)
+ if (THIS_KERNEL_VERSION >= LINUX(5,12,0)){
+ if((ret = get_kernel_config("CONFIG_ARM64_64K_PAGES", NULL)) == IKCONFIG_Y)
+ machdep->section_size_bits = 29;
+ else
+ machdep->section_size_bits = 27;
+ }
+ else if ((ret = get_kernel_config("CONFIG_HOTPLUG_SIZE_BITS", &string)) == IKCONFIG_STR)
machdep->section_size_bits = atol(string);
- }
+ }
}
if (CRASHDEBUG(1))
--
2.7.4
3 years
Re: [Crash-utility] [PATCH 1/1] Handle task_struct cpu member changes in linux-next
by lijiang
On Thu, Oct 14, 2021 at 12:03 AM <crash-utility-request(a)redhat.com> wrote:
> Date: Wed, 13 Oct 2021 10:56:39 +0200
> From: Alexander Egorenkov <egorenar(a)linux.ibm.com>
> To: crash-utility(a)redhat.com
> Subject: [Crash-utility] [PATCH 1/1] Handle task_struct cpu member
> changes in linux-next
> Message-ID: <20211013085639.192233-1-egorenar(a)linux.ibm.com>
> Content-Type: text/plain; charset="US-ASCII"
>
> Kernel commit bcf9033e5449bdcaa9bed46467a7141a8049dadb
> ("sched: move CPU field back into thread_info if THREAD_INFO_IN_TASK=y")
> moved the member cpu of task_struct back into thread_info.
>
> https://lkml.org/lkml/2021/9/30/517
>
> This fixes the following problem:
>
> please wait... (gathering task table data)
> crash: invalid structure member offset: task_struct_cpu
> FILE: task.c LINE: 2904 FUNCTION: add_context()
>
> [/usr/bin/crash] error trace: 114840a => 115560a => 114e360 => 11d6394
>
> 11d6394: (undetermined)
> 114e360: (undetermined)
> 115560a: (undetermined)
> 114840a: task_init+4634
>
> Signed-off-by: Alexander Egorenkov <egorenar(a)linux.ibm.com>
> ---
> task.c | 7 ++++---
> 1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/task.c b/task.c
> index 672b41697e75..bb6a5da8ad33 100644
> --- a/task.c
> +++ b/task.c
> @@ -278,8 +278,10 @@ task_init(void)
> } else if (VALID_MEMBER(task_struct_stack))
> MEMBER_OFFSET_INIT(task_struct_thread_info, "task_struct", "stack");
>
> + MEMBER_OFFSET_INIT(task_struct_cpu, "task_struct", "cpu");
> +
> if (VALID_MEMBER(task_struct_thread_info)) {
> - if (tt->flags & THREAD_INFO_IN_TASK) {
> + if (tt->flags & THREAD_INFO_IN_TASK && VALID_MEMBER(task_struct_cpu)) {
> MEMBER_OFFSET_INIT(thread_info_flags, "thread_info", "flags");
> /* (unnecessary) reminders */
> ASSIGN_OFFSET(thread_info_task) = INVALID_OFFSET;
> @@ -315,7 +317,6 @@ task_init(void)
> MEMBER_OFFSET_INIT(task_struct_has_cpu, "task_struct", "has_cpu");
> MEMBER_OFFSET_INIT(task_struct_cpus_runnable,
> "task_struct", "cpus_runnable");
> - MEMBER_OFFSET_INIT(task_struct_cpu, "task_struct", "cpu");
> MEMBER_OFFSET_INIT(task_struct_active_mm, "task_struct", "active_mm");
> MEMBER_OFFSET_INIT(task_struct_next_run, "task_struct", "next_run");
> MEMBER_OFFSET_INIT(task_struct_flags, "task_struct", "flags");
> @@ -2900,7 +2901,7 @@ add_context(ulong task, char *tp)
> else
> tc->thread_info = ULONG(tp + OFFSET(task_struct_thread_info));
> fill_thread_info(tc->thread_info);
> - if (tt->flags & THREAD_INFO_IN_TASK)
> + if (tt->flags & THREAD_INFO_IN_TASK && VALID_MEMBER(task_struct_cpu))
> processor_addr = (int *) (tp + OFFSET(task_struct_cpu));
> else
> processor_addr = (int *) (tt->thread_info +
> --
> 2.31.1
Thank you for the fix, Alexander.
Acked-by: Lianbo Jiang <lijiang(a)redhat.com>
3 years