linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] perf/record: Fix module size on s390
@ 2019-07-24 12:27 Thomas Richter
  2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Thomas Richter @ 2019-07-24 12:27 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: brueckner, gor, heiko.carstens, Thomas Richter, stable

On s390 the modules loaded in memory have the text segment
located after the GOT and Relocation table. This can be seen
with this output:
  [root@m35lp76 perf]# fgrep qeth /proc/modules
  qeth 151552 1 qeth_l2, Live 0x000003ff800b2000
  ...
  [root@m35lp76 perf]# cat /sys/module/qeth/sections/.text
  0x000003ff800b3990
  [root@m35lp76 perf]#

There is an offset of 0x1990 bytes. The size of the qeth module
is 151552 bytes (0x25000 in hex).
The location of the GOT/relocation table at the beginning of a
module is unique to s390.

commit 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
adjusts the start address of a module in the map structures, but
does not adjust the size of the modules. This leads to overlapping
of module maps as this example shows:

[root@m35lp76 perf] # ./perf report -D
     0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x25000)
          @ 0]:  x /lib/modules/.../qeth.ko.xz
     0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x8000)
          @ 0]:  x /lib/modules/.../ip6_tables.ko.xz

The module qeth.ko has an adjusted start address modified to b3990,
but its size is unchanged and the module ends at 0x3ff800d8990.
This end address overlaps with the next modules start address of
0x3ff800d85a0.

When the size of the leading GOT/Relocation table stored in the
beginning of the text segment (0x1990 bytes) is subtracted from
module qeth end address, there are no overlaps anymore:

   0x3ff800d8990 - 0x1990 = 0x0x3ff800d7000

which is the same as

   0x3ff800b2000 + 0x25000 = 0x0x3ff800d7000.

To fix this issue, also adjust the modules size in function
arch__fix_module_text_start(). Add another function parameter
named size and reduce the size of the module when the text segment
start address is changed.

Output after:
     0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x23670)
          @ 0]:  x /lib/modules/.../qeth.ko.xz
     0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x7a60)
          @ 0]:  x /lib/modules/.../ip6_tables.ko.xz

Fixes: 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
Cc: <stable@vger.kernel.org> # v4.9+
Reported-by: Stefan Liebler <stli@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 tools/perf/arch/s390/util/machine.c | 14 +++++++++++++-
 tools/perf/util/machine.c           |  3 ++-
 tools/perf/util/machine.h           |  2 +-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
index a19690a17291..de26b1441a48 100644
--- a/tools/perf/arch/s390/util/machine.c
+++ b/tools/perf/arch/s390/util/machine.c
@@ -7,7 +7,7 @@
 #include "api/fs/fs.h"
 #include "debug.h"
 
-int arch__fix_module_text_start(u64 *start, const char *name)
+int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 {
 	u64 m_start = *start;
 	char path[PATH_MAX];
@@ -17,6 +17,18 @@ int arch__fix_module_text_start(u64 *start, const char *name)
 	if (sysfs__read_ull(path, (unsigned long long *)start) < 0) {
 		pr_debug2("Using module %s start:%#lx\n", path, m_start);
 		*start = m_start;
+	} else {
+		/* Successful read of the modules segment text start address.
+		 * Calculate difference between module start address
+		 * in memory and module text segment start address.
+		 * For example module load address is 0x3ff8011b000
+		 * (from /proc/modules) and module text segment start
+		 * address is 0x3ff8011b870 (from file above).
+		 *
+		 * Adjust the module size and subtract the GOT table
+		 * size located at the beginning of the module.
+		 */
+		*size -= (*start - m_start);
 	}
 
 	return 0;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index dc7aafe45a2b..081fe4bdebaa 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1365,6 +1365,7 @@ static int machine__set_modules_path(struct machine *machine)
 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
 }
 int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
+				u64 *size __maybe_unused,
 				const char *name __maybe_unused)
 {
 	return 0;
@@ -1376,7 +1377,7 @@ static int machine__create_module(void *arg, const char *name, u64 start,
 	struct machine *machine = arg;
 	struct map *map;
 
-	if (arch__fix_module_text_start(&start, name) < 0)
+	if (arch__fix_module_text_start(&start, &size, name) < 0)
 		return -1;
 
 	map = machine__findnew_module_map(machine, start, name);
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index f70ab98a7bde..7aa38da26427 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -222,7 +222,7 @@ struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
 
 struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 					const char *filename);
-int arch__fix_module_text_start(u64 *start, const char *name);
+int arch__fix_module_text_start(u64 *start, u64 *size, const char *name);
 
 int machine__load_kallsyms(struct machine *machine, const char *filename);
 
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start
  2019-07-24 12:27 [PATCH 1/2] perf/record: Fix module size on s390 Thomas Richter
@ 2019-07-24 12:27 ` Thomas Richter
  2019-08-08 13:49   ` Arnaldo Carvalho de Melo
  2019-08-08 20:22   ` [tip:perf/urgent] perf annotate: " tip-bot for Thomas Richter
  2019-08-08 13:47 ` [PATCH 1/2] perf/record: Fix module size on s390 Arnaldo Carvalho de Melo
  2019-08-08 20:21 ` [tip:perf/urgent] perf record: " tip-bot for Thomas Richter
  2 siblings, 2 replies; 6+ messages in thread
From: Thomas Richter @ 2019-07-24 12:27 UTC (permalink / raw)
  To: linux-kernel, linux-perf-users, acme
  Cc: brueckner, gor, heiko.carstens, Thomas Richter, stable

During execution of command 'perf top' the error message:

   Not enough memory for annotating '__irf_end' symbol!)

is emitted from this call sequence:
  __cmd_top
    perf_top__mmap_read
      perf_top__mmap_read_idx
        perf_event__process_sample
          hist_entry_iter__add
            hist_iter__top_callback
              perf_top__record_precise_ip
                hist_entry__inc_addr_samples
                  symbol__inc_addr_samples
                    symbol__get_annotation
                      symbol__alloc_hist

In this function the size of symbol __irf_end is calculated. The size
of a symbol is the difference between its start and end address.
When the symbol was read the first time, its start and end was set to:
   symbol__new: __irf_end 0xe954d0-0xe954d0
which is correct and maps with /proc/kallsyms:

   root@s8360046:~/linux-4.15.0/tools/perf# fgrep _irf_end /proc/kallsyms
   0000000000e954d0 t __irf_end
   root@s8360046:~/linux-4.15.0/tools/perf#

In function symbol__alloc_hist() the end of symbol __irf_end is

  symbol__alloc_hist sym:__irf_end start:0xe954d0 end:0x3ff80045a8

which is identical with the first module entry in /proc/kallsyms

This results in a symbol size of __irf_req for histogram analyses of
70334140059072 bytes and a malloc() for this requested size fails.

The root cause of this is function
  __dso__load_kallsyms()
  +-> symbols__fixup_end()

Function symbols__fixup_end() enlarges the last symbol in the
kallsyms map
   # fgrep __irf_end /proc/kallsyms
   0000000000e954d0 t __irf_end
   #

to the start address of the first module:
   # cat /proc/kallsyms | sort  | egrep ' [tT] '
   ....
   0000000000e952d0 T __security_initcall_end
   0000000000e954d0 T __initramfs_size
   0000000000e954d0 t __irf_end
   000003ff800045a8 T fc_get_event_number       [scsi_transport_fc]
   000003ff800045d0 t store_fc_vport_disable    [scsi_transport_fc]
   000003ff800046a8 T scsi_is_fc_rport  [scsi_transport_fc]
   000003ff800046d0 t fc_target_setup   [scsi_transport_fc]

On s390 the kernel is located around memory address 0x200, 0x10000
or 0x100000, depending on linux version. Modules however start some-
where around 0x3ff xxxx xxxx.

This is different than x86 and produces a large gap for which
histogram allocation fails.

Fix this by detecting the kernel's last symbol and do no
adjustment for it. Introduce a weak function and handle s390 specifics.

Cc: <stable@vger.kernel.org>
Reported-by: Klaus Theurich <klaus.theurich@de.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
---
 tools/perf/arch/s390/util/machine.c | 17 +++++++++++++++++
 tools/perf/util/symbol.c            |  7 ++++++-
 tools/perf/util/symbol.h            |  1 +
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
index de26b1441a48..c8c86a0c9b79 100644
--- a/tools/perf/arch/s390/util/machine.c
+++ b/tools/perf/arch/s390/util/machine.c
@@ -6,6 +6,7 @@
 #include "machine.h"
 #include "api/fs/fs.h"
 #include "debug.h"
+#include "symbol.h"
 
 int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 {
@@ -33,3 +34,19 @@ int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 
 	return 0;
 }
+
+/* On s390 kernel text segment start is located at very low memory addresses,
+ * for example 0x10000. Modules are located at very high memory addresses,
+ * for example 0x3ff xxxx xxxx. The gap between end of kernel text segment
+ * and beginning of first module's text segment is very big.
+ * Therefore do not fill this gap and do not assign it to the kernel dso map.
+ */
+void arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
+{
+	if (strchr(p->name, '[') == NULL && strchr(c->name, '['))
+		/* Last kernel symbol mapped to end of page */
+		p->end = roundup(p->end, page_size);
+	else
+		p->end = c->start;
+	pr_debug4("%s sym:%s end:%#lx\n", __func__, p->name, p->end);
+}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 5cbad55cd99d..3b49eb4e3ed9 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -91,6 +91,11 @@ static int prefix_underscores_count(const char *str)
 	return tail - str;
 }
 
+void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
+{
+	p->end = c->start;
+}
+
 const char * __weak arch__normalize_symbol_name(const char *name)
 {
 	return name;
@@ -217,7 +222,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols)
 		curr = rb_entry(nd, struct symbol, rb_node);
 
 		if (prev->end == prev->start && prev->end != curr->start)
-			prev->end = curr->start;
+			arch__symbols__fixup_end(prev, curr);
 	}
 
 	/* Last entry */
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 9a8fe012910a..f30ab608ea54 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -277,6 +277,7 @@ const char *arch__normalize_symbol_name(const char *name);
 #define SYMBOL_A 0
 #define SYMBOL_B 1
 
+void arch__symbols__fixup_end(struct symbol *p, struct symbol *c);
 int arch__compare_symbol_names(const char *namea, const char *nameb);
 int arch__compare_symbol_names_n(const char *namea, const char *nameb,
 				 unsigned int n);
-- 
2.21.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/2] perf/record: Fix module size on s390
  2019-07-24 12:27 [PATCH 1/2] perf/record: Fix module size on s390 Thomas Richter
  2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
@ 2019-08-08 13:47 ` Arnaldo Carvalho de Melo
  2019-08-08 20:21 ` [tip:perf/urgent] perf record: " tip-bot for Thomas Richter
  2 siblings, 0 replies; 6+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-08-08 13:47 UTC (permalink / raw)
  To: Thomas Richter
  Cc: linux-kernel, linux-perf-users, brueckner, gor, heiko.carstens, stable

Em Wed, Jul 24, 2019 at 02:27:02PM +0200, Thomas Richter escreveu:
> On s390 the modules loaded in memory have the text segment
> located after the GOT and Relocation table. This can be seen
> with this output:
>   [root@m35lp76 perf]# fgrep qeth /proc/modules
>   qeth 151552 1 qeth_l2, Live 0x000003ff800b2000
>   ...
>   [root@m35lp76 perf]# cat /sys/module/qeth/sections/.text
>   0x000003ff800b3990
>   [root@m35lp76 perf]#

Thanks, applied.

- Arnaldo
 
> There is an offset of 0x1990 bytes. The size of the qeth module
> is 151552 bytes (0x25000 in hex).
> The location of the GOT/relocation table at the beginning of a
> module is unique to s390.
> 
> commit 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
> adjusts the start address of a module in the map structures, but
> does not adjust the size of the modules. This leads to overlapping
> of module maps as this example shows:
> 
> [root@m35lp76 perf] # ./perf report -D
>      0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x25000)
>           @ 0]:  x /lib/modules/.../qeth.ko.xz
>      0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x8000)
>           @ 0]:  x /lib/modules/.../ip6_tables.ko.xz
> 
> The module qeth.ko has an adjusted start address modified to b3990,
> but its size is unchanged and the module ends at 0x3ff800d8990.
> This end address overlaps with the next modules start address of
> 0x3ff800d85a0.
> 
> When the size of the leading GOT/Relocation table stored in the
> beginning of the text segment (0x1990 bytes) is subtracted from
> module qeth end address, there are no overlaps anymore:
> 
>    0x3ff800d8990 - 0x1990 = 0x0x3ff800d7000
> 
> which is the same as
> 
>    0x3ff800b2000 + 0x25000 = 0x0x3ff800d7000.
> 
> To fix this issue, also adjust the modules size in function
> arch__fix_module_text_start(). Add another function parameter
> named size and reduce the size of the module when the text segment
> start address is changed.
> 
> Output after:
>      0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x23670)
>           @ 0]:  x /lib/modules/.../qeth.ko.xz
>      0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x7a60)
>           @ 0]:  x /lib/modules/.../ip6_tables.ko.xz
> 
> Fixes: 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
> Cc: <stable@vger.kernel.org> # v4.9+
> Reported-by: Stefan Liebler <stli@linux.ibm.com>
> Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
> ---
>  tools/perf/arch/s390/util/machine.c | 14 +++++++++++++-
>  tools/perf/util/machine.c           |  3 ++-
>  tools/perf/util/machine.h           |  2 +-
>  3 files changed, 16 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
> index a19690a17291..de26b1441a48 100644
> --- a/tools/perf/arch/s390/util/machine.c
> +++ b/tools/perf/arch/s390/util/machine.c
> @@ -7,7 +7,7 @@
>  #include "api/fs/fs.h"
>  #include "debug.h"
>  
> -int arch__fix_module_text_start(u64 *start, const char *name)
> +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
>  {
>  	u64 m_start = *start;
>  	char path[PATH_MAX];
> @@ -17,6 +17,18 @@ int arch__fix_module_text_start(u64 *start, const char *name)
>  	if (sysfs__read_ull(path, (unsigned long long *)start) < 0) {
>  		pr_debug2("Using module %s start:%#lx\n", path, m_start);
>  		*start = m_start;
> +	} else {
> +		/* Successful read of the modules segment text start address.
> +		 * Calculate difference between module start address
> +		 * in memory and module text segment start address.
> +		 * For example module load address is 0x3ff8011b000
> +		 * (from /proc/modules) and module text segment start
> +		 * address is 0x3ff8011b870 (from file above).
> +		 *
> +		 * Adjust the module size and subtract the GOT table
> +		 * size located at the beginning of the module.
> +		 */
> +		*size -= (*start - m_start);
>  	}
>  
>  	return 0;
> diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
> index dc7aafe45a2b..081fe4bdebaa 100644
> --- a/tools/perf/util/machine.c
> +++ b/tools/perf/util/machine.c
> @@ -1365,6 +1365,7 @@ static int machine__set_modules_path(struct machine *machine)
>  	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
>  }
>  int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
> +				u64 *size __maybe_unused,
>  				const char *name __maybe_unused)
>  {
>  	return 0;
> @@ -1376,7 +1377,7 @@ static int machine__create_module(void *arg, const char *name, u64 start,
>  	struct machine *machine = arg;
>  	struct map *map;
>  
> -	if (arch__fix_module_text_start(&start, name) < 0)
> +	if (arch__fix_module_text_start(&start, &size, name) < 0)
>  		return -1;
>  
>  	map = machine__findnew_module_map(machine, start, name);
> diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
> index f70ab98a7bde..7aa38da26427 100644
> --- a/tools/perf/util/machine.h
> +++ b/tools/perf/util/machine.h
> @@ -222,7 +222,7 @@ struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
>  
>  struct map *machine__findnew_module_map(struct machine *machine, u64 start,
>  					const char *filename);
> -int arch__fix_module_text_start(u64 *start, const char *name);
> +int arch__fix_module_text_start(u64 *start, u64 *size, const char *name);
>  
>  int machine__load_kallsyms(struct machine *machine, const char *filename);
>  
> -- 
> 2.21.0

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start
  2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
@ 2019-08-08 13:49   ` Arnaldo Carvalho de Melo
  2019-08-08 20:22   ` [tip:perf/urgent] perf annotate: " tip-bot for Thomas Richter
  1 sibling, 0 replies; 6+ messages in thread
From: Arnaldo Carvalho de Melo @ 2019-08-08 13:49 UTC (permalink / raw)
  To: Thomas Richter
  Cc: linux-kernel, linux-perf-users, brueckner, gor, heiko.carstens, stable

Em Wed, Jul 24, 2019 at 02:27:03PM +0200, Thomas Richter escreveu:
> During execution of command 'perf top' the error message:
> 
>    Not enough memory for annotating '__irf_end' symbol!)
> 
> is emitted from this call sequence:
>   __cmd_top
>     perf_top__mmap_read
>       perf_top__mmap_read_idx
>         perf_event__process_sample
>           hist_entry_iter__add
>             hist_iter__top_callback
>               perf_top__record_precise_ip
>                 hist_entry__inc_addr_samples
>                   symbol__inc_addr_samples
>                     symbol__get_annotation
>                       symbol__alloc_hist

Thanks, applied.

- Arnaldo
 
> In this function the size of symbol __irf_end is calculated. The size
> of a symbol is the difference between its start and end address.
> When the symbol was read the first time, its start and end was set to:
>    symbol__new: __irf_end 0xe954d0-0xe954d0
> which is correct and maps with /proc/kallsyms:
> 
>    root@s8360046:~/linux-4.15.0/tools/perf# fgrep _irf_end /proc/kallsyms
>    0000000000e954d0 t __irf_end
>    root@s8360046:~/linux-4.15.0/tools/perf#
> 
> In function symbol__alloc_hist() the end of symbol __irf_end is
> 
>   symbol__alloc_hist sym:__irf_end start:0xe954d0 end:0x3ff80045a8
> 
> which is identical with the first module entry in /proc/kallsyms
> 
> This results in a symbol size of __irf_req for histogram analyses of
> 70334140059072 bytes and a malloc() for this requested size fails.
> 
> The root cause of this is function
>   __dso__load_kallsyms()
>   +-> symbols__fixup_end()
> 
> Function symbols__fixup_end() enlarges the last symbol in the
> kallsyms map
>    # fgrep __irf_end /proc/kallsyms
>    0000000000e954d0 t __irf_end
>    #
> 
> to the start address of the first module:
>    # cat /proc/kallsyms | sort  | egrep ' [tT] '
>    ....
>    0000000000e952d0 T __security_initcall_end
>    0000000000e954d0 T __initramfs_size
>    0000000000e954d0 t __irf_end
>    000003ff800045a8 T fc_get_event_number       [scsi_transport_fc]
>    000003ff800045d0 t store_fc_vport_disable    [scsi_transport_fc]
>    000003ff800046a8 T scsi_is_fc_rport  [scsi_transport_fc]
>    000003ff800046d0 t fc_target_setup   [scsi_transport_fc]
> 
> On s390 the kernel is located around memory address 0x200, 0x10000
> or 0x100000, depending on linux version. Modules however start some-
> where around 0x3ff xxxx xxxx.
> 
> This is different than x86 and produces a large gap for which
> histogram allocation fails.
> 
> Fix this by detecting the kernel's last symbol and do no
> adjustment for it. Introduce a weak function and handle s390 specifics.
> 
> Cc: <stable@vger.kernel.org>
> Reported-by: Klaus Theurich <klaus.theurich@de.ibm.com>
> Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
> Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
> ---
>  tools/perf/arch/s390/util/machine.c | 17 +++++++++++++++++
>  tools/perf/util/symbol.c            |  7 ++++++-
>  tools/perf/util/symbol.h            |  1 +
>  3 files changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
> index de26b1441a48..c8c86a0c9b79 100644
> --- a/tools/perf/arch/s390/util/machine.c
> +++ b/tools/perf/arch/s390/util/machine.c
> @@ -6,6 +6,7 @@
>  #include "machine.h"
>  #include "api/fs/fs.h"
>  #include "debug.h"
> +#include "symbol.h"
>  
>  int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
>  {
> @@ -33,3 +34,19 @@ int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
>  
>  	return 0;
>  }
> +
> +/* On s390 kernel text segment start is located at very low memory addresses,
> + * for example 0x10000. Modules are located at very high memory addresses,
> + * for example 0x3ff xxxx xxxx. The gap between end of kernel text segment
> + * and beginning of first module's text segment is very big.
> + * Therefore do not fill this gap and do not assign it to the kernel dso map.
> + */
> +void arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
> +{
> +	if (strchr(p->name, '[') == NULL && strchr(c->name, '['))
> +		/* Last kernel symbol mapped to end of page */
> +		p->end = roundup(p->end, page_size);
> +	else
> +		p->end = c->start;
> +	pr_debug4("%s sym:%s end:%#lx\n", __func__, p->name, p->end);
> +}
> diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
> index 5cbad55cd99d..3b49eb4e3ed9 100644
> --- a/tools/perf/util/symbol.c
> +++ b/tools/perf/util/symbol.c
> @@ -91,6 +91,11 @@ static int prefix_underscores_count(const char *str)
>  	return tail - str;
>  }
>  
> +void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
> +{
> +	p->end = c->start;
> +}
> +
>  const char * __weak arch__normalize_symbol_name(const char *name)
>  {
>  	return name;
> @@ -217,7 +222,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols)
>  		curr = rb_entry(nd, struct symbol, rb_node);
>  
>  		if (prev->end == prev->start && prev->end != curr->start)
> -			prev->end = curr->start;
> +			arch__symbols__fixup_end(prev, curr);
>  	}
>  
>  	/* Last entry */
> diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
> index 9a8fe012910a..f30ab608ea54 100644
> --- a/tools/perf/util/symbol.h
> +++ b/tools/perf/util/symbol.h
> @@ -277,6 +277,7 @@ const char *arch__normalize_symbol_name(const char *name);
>  #define SYMBOL_A 0
>  #define SYMBOL_B 1
>  
> +void arch__symbols__fixup_end(struct symbol *p, struct symbol *c);
>  int arch__compare_symbol_names(const char *namea, const char *nameb);
>  int arch__compare_symbol_names_n(const char *namea, const char *nameb,
>  				 unsigned int n);
> -- 
> 2.21.0

-- 

- Arnaldo

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [tip:perf/urgent] perf record: Fix module size on s390
  2019-07-24 12:27 [PATCH 1/2] perf/record: Fix module size on s390 Thomas Richter
  2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
  2019-08-08 13:47 ` [PATCH 1/2] perf/record: Fix module size on s390 Arnaldo Carvalho de Melo
@ 2019-08-08 20:21 ` tip-bot for Thomas Richter
  2 siblings, 0 replies; 6+ messages in thread
From: tip-bot for Thomas Richter @ 2019-08-08 20:21 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: tglx, tmricht, brueckner, linux-kernel, hpa, heiko.carstens,
	mingo, acme, stli, gor

Commit-ID:  12a6d2940b5f02b4b9f71ce098e3bb02bc24a9ea
Gitweb:     https://git.kernel.org/tip/12a6d2940b5f02b4b9f71ce098e3bb02bc24a9ea
Author:     Thomas Richter <tmricht@linux.ibm.com>
AuthorDate: Wed, 24 Jul 2019 14:27:02 +0200
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 8 Aug 2019 15:41:11 -0300

perf record: Fix module size on s390

On s390 the modules loaded in memory have the text segment located after
the GOT and Relocation table. This can be seen with this output:

  [root@m35lp76 perf]# fgrep qeth /proc/modules
  qeth 151552 1 qeth_l2, Live 0x000003ff800b2000
  ...
  [root@m35lp76 perf]# cat /sys/module/qeth/sections/.text
  0x000003ff800b3990
  [root@m35lp76 perf]#

There is an offset of 0x1990 bytes. The size of the qeth module is
151552 bytes (0x25000 in hex).

The location of the GOT/relocation table at the beginning of a module is
unique to s390.

commit 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
adjusts the start address of a module in the map structures, but does
not adjust the size of the modules. This leads to overlapping of module
maps as this example shows:

[root@m35lp76 perf] # ./perf report -D
     0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x25000)
          @ 0]:  x /lib/modules/.../qeth.ko.xz
     0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x8000)
          @ 0]:  x /lib/modules/.../ip6_tables.ko.xz

The module qeth.ko has an adjusted start address modified to b3990, but
its size is unchanged and the module ends at 0x3ff800d8990.  This end
address overlaps with the next modules start address of 0x3ff800d85a0.

When the size of the leading GOT/Relocation table stored in the
beginning of the text segment (0x1990 bytes) is subtracted from module
qeth end address, there are no overlaps anymore:

   0x3ff800d8990 - 0x1990 = 0x0x3ff800d7000

which is the same as

   0x3ff800b2000 + 0x25000 = 0x0x3ff800d7000.

To fix this issue, also adjust the modules size in function
arch__fix_module_text_start(). Add another function parameter named size
and reduce the size of the module when the text segment start address is
changed.

Output after:
     0 0 0xfb0 [0xa0]: PERF_RECORD_MMAP -1/0: [0x3ff800b3990(0x23670)
          @ 0]:  x /lib/modules/.../qeth.ko.xz
     0 0 0x1050 [0xb0]: PERF_RECORD_MMAP -1/0: [0x3ff800d85a0(0x7a60)
          @ 0]:  x /lib/modules/.../ip6_tables.ko.xz

Reported-by: Stefan Liebler <stli@linux.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Hendrik Brueckner <brueckner@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: stable@vger.kernel.org
Fixes: 203d8a4aa6ed ("perf s390: Fix 'start' address of module's map")
Link: http://lkml.kernel.org/r/20190724122703.3996-1-tmricht@linux.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/s390/util/machine.c | 14 +++++++++++++-
 tools/perf/util/machine.c           |  3 ++-
 tools/perf/util/machine.h           |  2 +-
 3 files changed, 16 insertions(+), 3 deletions(-)

diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
index a19690a17291..de26b1441a48 100644
--- a/tools/perf/arch/s390/util/machine.c
+++ b/tools/perf/arch/s390/util/machine.c
@@ -7,7 +7,7 @@
 #include "api/fs/fs.h"
 #include "debug.h"
 
-int arch__fix_module_text_start(u64 *start, const char *name)
+int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 {
 	u64 m_start = *start;
 	char path[PATH_MAX];
@@ -17,6 +17,18 @@ int arch__fix_module_text_start(u64 *start, const char *name)
 	if (sysfs__read_ull(path, (unsigned long long *)start) < 0) {
 		pr_debug2("Using module %s start:%#lx\n", path, m_start);
 		*start = m_start;
+	} else {
+		/* Successful read of the modules segment text start address.
+		 * Calculate difference between module start address
+		 * in memory and module text segment start address.
+		 * For example module load address is 0x3ff8011b000
+		 * (from /proc/modules) and module text segment start
+		 * address is 0x3ff8011b870 (from file above).
+		 *
+		 * Adjust the module size and subtract the GOT table
+		 * size located at the beginning of the module.
+		 */
+		*size -= (*start - m_start);
 	}
 
 	return 0;
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index cf826eca3aaf..83b2fbbeeb90 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -1378,6 +1378,7 @@ static int machine__set_modules_path(struct machine *machine)
 	return map_groups__set_modules_path_dir(&machine->kmaps, modules_path, 0);
 }
 int __weak arch__fix_module_text_start(u64 *start __maybe_unused,
+				u64 *size __maybe_unused,
 				const char *name __maybe_unused)
 {
 	return 0;
@@ -1389,7 +1390,7 @@ static int machine__create_module(void *arg, const char *name, u64 start,
 	struct machine *machine = arg;
 	struct map *map;
 
-	if (arch__fix_module_text_start(&start, name) < 0)
+	if (arch__fix_module_text_start(&start, &size, name) < 0)
 		return -1;
 
 	map = machine__findnew_module_map(machine, start, name);
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index f70ab98a7bde..7aa38da26427 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -222,7 +222,7 @@ struct symbol *machine__find_kernel_symbol_by_name(struct machine *machine,
 
 struct map *machine__findnew_module_map(struct machine *machine, u64 start,
 					const char *filename);
-int arch__fix_module_text_start(u64 *start, const char *name);
+int arch__fix_module_text_start(u64 *start, u64 *size, const char *name);
 
 int machine__load_kallsyms(struct machine *machine, const char *filename);
 

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [tip:perf/urgent] perf annotate: Fix s390 gap between kernel end and module start
  2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
  2019-08-08 13:49   ` Arnaldo Carvalho de Melo
@ 2019-08-08 20:22   ` tip-bot for Thomas Richter
  1 sibling, 0 replies; 6+ messages in thread
From: tip-bot for Thomas Richter @ 2019-08-08 20:22 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: brueckner, tmricht, hpa, linux-kernel, tglx, heiko.carstens,
	acme, gor, mingo, klaus.theurich

Commit-ID:  b9c0a64901d5bdec6eafd38d1dc8fa0e2974fccb
Gitweb:     https://git.kernel.org/tip/b9c0a64901d5bdec6eafd38d1dc8fa0e2974fccb
Author:     Thomas Richter <tmricht@linux.ibm.com>
AuthorDate: Wed, 24 Jul 2019 14:27:03 +0200
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Thu, 8 Aug 2019 15:41:25 -0300

perf annotate: Fix s390 gap between kernel end and module start

During execution of command 'perf top' the error message:

   Not enough memory for annotating '__irf_end' symbol!)

is emitted from this call sequence:
  __cmd_top
    perf_top__mmap_read
      perf_top__mmap_read_idx
        perf_event__process_sample
          hist_entry_iter__add
            hist_iter__top_callback
              perf_top__record_precise_ip
                hist_entry__inc_addr_samples
                  symbol__inc_addr_samples
                    symbol__get_annotation
                      symbol__alloc_hist

In this function the size of symbol __irf_end is calculated. The size of
a symbol is the difference between its start and end address.

When the symbol was read the first time, its start and end was set to:

   symbol__new: __irf_end 0xe954d0-0xe954d0

which is correct and maps with /proc/kallsyms:

   root@s8360046:~/linux-4.15.0/tools/perf# fgrep _irf_end /proc/kallsyms
   0000000000e954d0 t __irf_end
   root@s8360046:~/linux-4.15.0/tools/perf#

In function symbol__alloc_hist() the end of symbol __irf_end is

  symbol__alloc_hist sym:__irf_end start:0xe954d0 end:0x3ff80045a8

which is identical with the first module entry in /proc/kallsyms

This results in a symbol size of __irf_req for histogram analyses of
70334140059072 bytes and a malloc() for this requested size fails.

The root cause of this is function
  __dso__load_kallsyms()
  +-> symbols__fixup_end()

Function symbols__fixup_end() enlarges the last symbol in the kallsyms
map:

   # fgrep __irf_end /proc/kallsyms
   0000000000e954d0 t __irf_end
   #

to the start address of the first module:
   # cat /proc/kallsyms | sort  | egrep ' [tT] '
   ....
   0000000000e952d0 T __security_initcall_end
   0000000000e954d0 T __initramfs_size
   0000000000e954d0 t __irf_end
   000003ff800045a8 T fc_get_event_number       [scsi_transport_fc]
   000003ff800045d0 t store_fc_vport_disable    [scsi_transport_fc]
   000003ff800046a8 T scsi_is_fc_rport  [scsi_transport_fc]
   000003ff800046d0 t fc_target_setup   [scsi_transport_fc]

On s390 the kernel is located around memory address 0x200, 0x10000 or
0x100000, depending on linux version. Modules however start some- where
around 0x3ff xxxx xxxx.

This is different than x86 and produces a large gap for which histogram
allocation fails.

Fix this by detecting the kernel's last symbol and do no adjustment for
it. Introduce a weak function and handle s390 specifics.

Reported-by: Klaus Theurich <klaus.theurich@de.ibm.com>
Signed-off-by: Thomas Richter <tmricht@linux.ibm.com>
Acked-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Hendrik Brueckner <brueckner@linux.ibm.com>
Cc: Vasily Gorbik <gor@linux.ibm.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/20190724122703.3996-2-tmricht@linux.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/arch/s390/util/machine.c | 17 +++++++++++++++++
 tools/perf/util/symbol.c            |  7 ++++++-
 tools/perf/util/symbol.h            |  1 +
 3 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/tools/perf/arch/s390/util/machine.c b/tools/perf/arch/s390/util/machine.c
index de26b1441a48..c8c86a0c9b79 100644
--- a/tools/perf/arch/s390/util/machine.c
+++ b/tools/perf/arch/s390/util/machine.c
@@ -6,6 +6,7 @@
 #include "machine.h"
 #include "api/fs/fs.h"
 #include "debug.h"
+#include "symbol.h"
 
 int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 {
@@ -33,3 +34,19 @@ int arch__fix_module_text_start(u64 *start, u64 *size, const char *name)
 
 	return 0;
 }
+
+/* On s390 kernel text segment start is located at very low memory addresses,
+ * for example 0x10000. Modules are located at very high memory addresses,
+ * for example 0x3ff xxxx xxxx. The gap between end of kernel text segment
+ * and beginning of first module's text segment is very big.
+ * Therefore do not fill this gap and do not assign it to the kernel dso map.
+ */
+void arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
+{
+	if (strchr(p->name, '[') == NULL && strchr(c->name, '['))
+		/* Last kernel symbol mapped to end of page */
+		p->end = roundup(p->end, page_size);
+	else
+		p->end = c->start;
+	pr_debug4("%s sym:%s end:%#lx\n", __func__, p->name, p->end);
+}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 173f3378aaa0..4efde7879474 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -92,6 +92,11 @@ static int prefix_underscores_count(const char *str)
 	return tail - str;
 }
 
+void __weak arch__symbols__fixup_end(struct symbol *p, struct symbol *c)
+{
+	p->end = c->start;
+}
+
 const char * __weak arch__normalize_symbol_name(const char *name)
 {
 	return name;
@@ -218,7 +223,7 @@ void symbols__fixup_end(struct rb_root_cached *symbols)
 		curr = rb_entry(nd, struct symbol, rb_node);
 
 		if (prev->end == prev->start && prev->end != curr->start)
-			prev->end = curr->start;
+			arch__symbols__fixup_end(prev, curr);
 	}
 
 	/* Last entry */
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 12755b42ea93..183f630cb5f1 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -288,6 +288,7 @@ const char *arch__normalize_symbol_name(const char *name);
 #define SYMBOL_A 0
 #define SYMBOL_B 1
 
+void arch__symbols__fixup_end(struct symbol *p, struct symbol *c);
 int arch__compare_symbol_names(const char *namea, const char *nameb);
 int arch__compare_symbol_names_n(const char *namea, const char *nameb,
 				 unsigned int n);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-08-08 20:22 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-24 12:27 [PATCH 1/2] perf/record: Fix module size on s390 Thomas Richter
2019-07-24 12:27 ` [PATCH 2/2] perf/top: Fix s390 gap between kernel end and module start Thomas Richter
2019-08-08 13:49   ` Arnaldo Carvalho de Melo
2019-08-08 20:22   ` [tip:perf/urgent] perf annotate: " tip-bot for Thomas Richter
2019-08-08 13:47 ` [PATCH 1/2] perf/record: Fix module size on s390 Arnaldo Carvalho de Melo
2019-08-08 20:21 ` [tip:perf/urgent] perf record: " tip-bot for Thomas Richter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).