Re: [PATCH] powerpc64/modules: fix ool-ftrace-stub vs. livepatch relocation corruption
From: Joe Lawrence <joe.lawrence@redhat.com>
Date: 2025-09-04 02:38:01
Also in:
live-patching
On Wed, Sep 03, 2025 at 10:29:50PM -0400, Joe Lawrence wrote:
The powerpc64 module .stubs section holds ppc64_stub_entry[] code trampolines that are generated at module load time. These stubs are necessary for function calls to external symbols that are too far away for a simple relative branch. Logic for finding an available ppc64_stub_entry has relied on a sentinel value in the funcdata member to indicate a used slot. Code iterates through the array, inspecting .funcdata to find the first unused (zeroed) entry: for (i = 0; stub_func_addr(stubs[i].funcdata); i++) To support CONFIG_PPC_FTRACE_OUT_OF_LINE, a new setup_ftrace_ool_stubs() function extended the .stubs section by adding an array of ftrace_ool_stub structures for each patchable function. A side effect of writing these smaller structures is that the funcdata sentinel convention is not maintained. This is not a problem for an ordinary kernel module, as this occurs in module_finalize(), after which no further .stubs updates are needed. However, when loading a livepatch module that contains klp-relocations, apply_relocate_add() is executed a second time, after the out-of-line ftrace stubs have been set up. When apply_relocate_add() then calls stub_for_addr() to handle a klp-relocation, its search for the next available ppc64_stub_entry[] slot may stop prematurely in the middle of the ftrace_ool_stub array. A full ppc64_stub_entry is then written, corrupting the ftrace stubs. Fix this by explicitly tracking the count of used ppc64_stub_entrys. Rather than relying on an inline funcdata sentinel value, a new stub_count is used as the explicit boundary for searching and allocating stubs. This simplifies the code, eliminates the "one extra reloc" that was required for the sentinel check, and resolves the memory corruption.
Apologies if this is too wordy, I wrote it as a bit of a braindump to summarize the longer analysis at the bottom of the reply ...
quoted hunk ↗ jump to hunk
Fixes: eec37961a56a ("powerpc64/ftrace: Move ftrace sequence out of line") Signed-off-by: Joe Lawrence <joe.lawrence@redhat.com> --- arch/powerpc/include/asm/module.h | 1 + arch/powerpc/kernel/module_64.c | 26 ++++++++------------------ 2 files changed, 9 insertions(+), 18 deletions(-)diff --git a/arch/powerpc/include/asm/module.h b/arch/powerpc/include/asm/module.h index e1ee5026ac4a..864e22deaa2c 100644 --- a/arch/powerpc/include/asm/module.h +++ b/arch/powerpc/include/asm/module.h@@ -27,6 +27,7 @@ struct ppc_plt_entry { struct mod_arch_specific { #ifdef __powerpc64__ unsigned int stubs_section; /* Index of stubs section in module */ + unsigned int stub_count; /* Number of stubs used */ #ifdef CONFIG_PPC_KERNEL_PCREL unsigned int got_section; /* What section is the GOT? */ unsigned int pcpu_section; /* .data..percpu section */diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c index 126bf3b06ab7..2a44bc8e2439 100644 --- a/arch/powerpc/kernel/module_64.c +++ b/arch/powerpc/kernel/module_64.c@@ -209,8 +209,7 @@ static unsigned long get_stubs_size(const Elf64_Ehdr *hdr, char *secstrings, struct module *me) { - /* One extra reloc so it's always 0-addr terminated */ - unsigned long relocs = 1; + unsigned long relocs = 0; unsigned i; /* Every relocated section... */@@ -705,7 +704,7 @@ static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs, /* Find this stub, or if that fails, the next avail. entry */ stubs = (void *)sechdrs[me->arch.stubs_section].sh_addr; - for (i = 0; stub_func_addr(stubs[i].funcdata); i++) { + for (i = 0; i < me->arch.stub_count; i++) { if (WARN_ON(i >= num_stubs)) return 0;@@ -716,6 +715,7 @@ static unsigned long stub_for_addr(const Elf64_Shdr *sechdrs, if (!create_stub(sechdrs, &stubs[i], addr, me, name)) return 0; + me->arch.stub_count++; return (unsigned long)&stubs[i]; }@@ -1118,29 +1118,19 @@ int module_trampoline_target(struct module *mod, unsigned long addr, static int setup_ftrace_ool_stubs(const Elf64_Shdr *sechdrs, unsigned long addr, struct module *me) { #ifdef CONFIG_PPC_FTRACE_OUT_OF_LINE - unsigned int i, total_stubs, num_stubs; + unsigned int total_stubs, num_stubs; struct ppc64_stub_entry *stub; total_stubs = sechdrs[me->arch.stubs_section].sh_size / sizeof(*stub); num_stubs = roundup(me->arch.ool_stub_count * sizeof(struct ftrace_ool_stub), sizeof(struct ppc64_stub_entry)) / sizeof(struct ppc64_stub_entry); - /* Find the next available entry */ - stub = (void *)sechdrs[me->arch.stubs_section].sh_addr; - for (i = 0; stub_func_addr(stub[i].funcdata); i++) - if (WARN_ON(i >= total_stubs)) - return -1; - - if (WARN_ON(i + num_stubs > total_stubs)) + if (WARN_ON(me->arch.stub_count + num_stubs > total_stubs)) return -1; - stub += i; - me->arch.ool_stubs = (struct ftrace_ool_stub *)stub; - - /* reserve stubs */ - for (i = 0; i < num_stubs; i++) - if (patch_u32((void *)&stub->funcdata, PPC_RAW_NOP())) - return -1;
At first I thought the bug was that this loop was re-writting the same PPC_RAW_NOP() to the same funcdata (i.e, should have been something like: patch_u32((void *)stub[i]->funcdata, PPC_RAW_NOP())), but that didn't work and seemed fragile anyway.
+ stub = (void *)sechdrs[me->arch.stubs_section].sh_addr; + me->arch.ool_stubs = (struct ftrace_ool_stub *)(stub + me->arch.stub_count); + me->arch.stub_count += num_stubs; #endif return 0; -- 2.50.1
Original problem
================
I noticed an issue when loading a livepatch module with a klp-relocation
(see Documentation/livepatch/module-elf-format.rst) and then tried
ftracing one of its functions:
$ SYSFS=/sys/kernel/debug/tracing
$ echo 0 > $SYSFS/tracing_on
$ echo > $SYSFS/set_ftrace_filter
$ echo function > $SYSFS/current_tracer
$ echo 'xfs_stats_format:mod:livepatch_module' >> $SYSFS/set_ftrace_filter
# Double check the ftrace filter
$ cat $SYSFS/set_ftrace_filter
xfs_stats_format [livepatch_module]
# Bombs away
$ echo 1 > $SYSFS/tracing_on
$ grep kpatch /sys/fs/xfs/stats/stats
[ ... sometimes a crash, sometimes nothing at all, but never a
$SYSFS/trace entry ... ]
This module is different from any of the in-kernel livepatching
kselftests as it was created by kpatch-build, and included a
klp-relocation:
$ readelf --wide --relocs livepatch-module.ko | awk '/.klp.rela.xfs..text.xfs_stats_format/' RS="\n\n"
Relocation section '.klp.rela.xfs..text.xfs_stats_format' at offset 0x18e010 contains 1 entry:
Offset Info Type Symbol's Value Symbol's Name + Addend
00000000000000d0 0000008c0000000a R_PPC64_REL24 0000000000000000 .klp.sym.xfs.counter_val,1 + 0
And when looking at the module's out-of-line ftrace stubs on a live system, I
saw the corruption.
crash utility analysis
----------------------
Dump the arch-specific module section to find the OOL-ftrace-sub area:
crash> mod | grep livepatch_module
c008000007d30500 livepatch_module c008000007d70000 262144 (not loaded) [CONFIG_KALLSYMS]
crash> struct module.arch c008000007d30500
arch = {
stubs_section = 72,
toc_section = 50,
toc_fixed = true,
tramp = 0xc008000007d70d80,
tramp_regs = 0xc008000007d70da8,
ool_stubs = 0xc008000007d70dd0 <xfs_stats_format+0x558>,
ool_stub_count = 7,
ool_stub_index = 7
},
Figure out how many instructions fit inside the ftrace_ool_stub[] area:
crash> p/d (sizeof(struct ftrace_ool_stub) * 7) / 4
$5 = 42
The crash utility disassembly below shows the memory corruption. After a
valid ftrace_ool_stub at index 1, a full ppc64_stub_entry for a
livepatch relocation has been incorrectly written at
xfs_stats_format+0x580, overwriting the memory where ftrace_ool_stub[1..3]
were supposed to be:
[ edited for readability: ppc64=ppc64_stub_entry and ftrace=ftrace_ool_stub ]
crash> dis 0xc008000007d70dd0 42
ppc64[ ] ftrace[0] <xfs_stats_format+0x558>: .long 0x0
<xfs_stats_format+0x55c>: .long 0x0
<xfs_stats_format+0x560>: mflr r0
<xfs_stats_format+0x564>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x568>: mtlr r0
<xfs_stats_format+0x56c>: b 0xc008000007d70014 <patch_free_livepatch+0xc>
ftrace[1] <xfs_stats_format+0x570>: .long 0x0
<xfs_stats_format+0x574>: .long 0x0
<xfs_stats_format+0x578>: mflr r0
<xfs_stats_format+0x57c>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
ppc64[ ] <xfs_stats_format+0x580>: addis r11,r2,4 << This looks like a full
<xfs_stats_format+0x584>: addi r11,r11,-29448 << ppc64_stub_entry
ftrace[2] <xfs_stats_format+0x588>: std r2,24(r1) << dropped in the middle
<xfs_stats_format+0x58c>: ld r12,32(r11) << of the ool_stubs array
<xfs_stats_format+0x590>: mtctr r12 << of ftrace_ool_stub[]
<xfs_stats_format+0x594>: bctr <<
<xfs_stats_format+0x598>: mtlr r0 <<
<xfs_stats_format+0x59c>: andi. r20,r27,30050 <<
ftrace[3] <xfs_stats_format+0x5a0>: .long 0x54e92b8 <<
<xfs_stats_format+0x5a4>: lfs f0,0(r8) <<
ppc64[ ] <xfs_stats_format+0x5a8>: mflr r0
<xfs_stats_format+0x5ac>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5b0>: mtlr r0
<xfs_stats_format+0x5b4>: b 0xc008000007d7037c <add_callbacks_to_patch_objects+0xc>
ftrace[4] <xfs_stats_format+0x5b8>: .long 0x0
<xfs_stats_format+0x5bc>: .long 0x0
<xfs_stats_format+0x5c0>: mflr r0
<xfs_stats_format+0x5c4>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5c8>: mtlr r0
<xfs_stats_format+0x5cc>: b 0xc008000007d705ac <init_module+0xc>
ppc64[ ] ftrace[5] <xfs_stats_format+0x5d0>: .long 0x0
<xfs_stats_format+0x5d4>: .long 0x0
<xfs_stats_format+0x5d8>: mflr r0
<xfs_stats_format+0x5dc>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5e0>: mtlr r0
<xfs_stats_format+0x5e4>: b 0xc008000007d70864 <kpatch_string+0xc>
ftrace[6] <xfs_stats_format+0x5e8>: .long 0x0
<xfs_stats_format+0x5ec>: .long 0x0
<xfs_stats_format+0x5f0>: mflr r0
<xfs_stats_format+0x5f4>: bl 0xc008000007d70d80 <xfs_stats_format+0x508>
ppc64[ ] <xfs_stats_format+0x5f8>: mtlr r0
<xfs_stats_format+0x5fc>: b 0xc008000007d70884 <xfs_stats_format+0xc>
crash utility analysis (post-fix)
--------------------------------
Get our bearings from the arch-specific section of the module:
crash> mod | grep livepatch_module
c008000009ae0500 livepatch_module c0080000099c0000 262144 (not loaded) [CONFIG_KALLSYMS]
crash> struct module.arch c008000009ae0500
arch = {
stubs_section = 72,
stub_count = 20, << new count of all ppc64_stub_entry[]
toc_section = 50,
toc_fixed = true,
tramp = 0xc0080000099c0d80,
tramp_regs = 0xc0080000099c0da8,
ool_stubs = 0xc0080000099c0dd0 <xfs_stats_format+0x558>, << where ftrace_ool_stub[] begins
ool_stub_count = 7, << count of ftrace_ool_stubs
ool_stub_index = 7
},
Disassmble the ftrace_ool_stub[] area for the livepatch_module. Figure out
how many instructions will fit into the ppc64_stub_entry and ftrace_ool_stub
structures so we can mark them along the way.
crash> p/d sizeof(struct ppc64_stub_entry) / 4
$1 = 10
crash> p/d sizeof(struct ftrace_ool_stub) / 4
$2 = 6
crash> p/d (sizeof(struct ppc64_stub_entry) * 20) / 4
$3 = 200
crash> dis 0xc0080000099c0ba0 200
The new disassembly shows that the regular relocation stubs
ppc64_stub_entry[0..13] are followed by the correctly formatted
ftrace_ool_stub area (ftrace_ool_stub[0..6]). The livepatch-specific
ppc64_stub_entry is now safely placed at the end of the section (at
ppc64_stub_entry[19]), avoiding any collision:
[ edited for readability: ppc64=ppc64_stub_entry and ftrace=ftrace_ool_stub ]
ppc64[0] <xfs_stats_format+0x328>: addis r11,r2,-18
<xfs_stats_format+0x32c>: addi r11,r11,-30048
<xfs_stats_format+0x330>: std r2,24(r1)
<xfs_stats_format+0x334>: ld r12,32(r11)
<xfs_stats_format+0x338>: mtctr r12
<xfs_stats_format+0x33c>: bctr
<xfs_stats_format+0x340>: .long 0x0
<xfs_stats_format+0x344>: andi. r20,r27,30050
<xfs_stats_format+0x348>: .long 0x123fef0
<xfs_stats_format+0x34c>: lfs f0,0(0)
ppc64[1] <xfs_stats_format+0x350>: addis r11,r2,-18
<xfs_stats_format+0x354>: addi r11,r11,-30008
<xfs_stats_format+0x358>: std r2,24(r1)
<xfs_stats_format+0x35c>: ld r12,32(r11)
<xfs_stats_format+0x360>: mtctr r12
<xfs_stats_format+0x364>: bctr
<xfs_stats_format+0x368>: .long 0x0
<xfs_stats_format+0x36c>: andi. r20,r27,30050
<xfs_stats_format+0x370>: .long 0xa7c9f0
<xfs_stats_format+0x374>: lfs f0,0(0)
ppc64[2] <xfs_stats_format+0x378>: addis r11,r2,-18
<xfs_stats_format+0x37c>: addi r11,r11,-29968
<xfs_stats_format+0x380>: std r2,24(r1)
<xfs_stats_format+0x384>: ld r12,32(r11)
<xfs_stats_format+0x388>: mtctr r12
<xfs_stats_format+0x38c>: bctr
<xfs_stats_format+0x390>: .long 0x0
<xfs_stats_format+0x394>: andi. r20,r27,30050
<xfs_stats_format+0x398>: .long 0x2f0a94
<xfs_stats_format+0x39c>: lfs f0,0(0)
ppc64[3] <xfs_stats_format+0x3a0>: addis r11,r2,-18
<xfs_stats_format+0x3a4>: addi r11,r11,-29928
<xfs_stats_format+0x3a8>: std r2,24(r1)
<xfs_stats_format+0x3ac>: ld r12,32(r11)
<xfs_stats_format+0x3b0>: mtctr r12
<xfs_stats_format+0x3b4>: bctr
<xfs_stats_format+0x3b8>: .long 0x0
<xfs_stats_format+0x3bc>: andi. r20,r27,30050
<xfs_stats_format+0x3c0>: .long 0x67e440
<xfs_stats_format+0x3c4>: lfs f0,0(0)
ppc64[4] <xfs_stats_format+0x3c8>: addis r11,r2,-18
<xfs_stats_format+0x3cc>: addi r11,r11,-29888
<xfs_stats_format+0x3d0>: std r2,24(r1)
<xfs_stats_format+0x3d4>: ld r12,32(r11)
<xfs_stats_format+0x3d8>: mtctr r12
<xfs_stats_format+0x3dc>: bctr
<xfs_stats_format+0x3e0>: .long 0x0
<xfs_stats_format+0x3e4>: andi. r20,r27,30050
<xfs_stats_format+0x3e8>: .long 0x683da0
<xfs_stats_format+0x3ec>: lfs f0,0(0)
ppc64[5] <xfs_stats_format+0x3f0>: addis r11,r2,-18
<xfs_stats_format+0x3f4>: addi r11,r11,-29848
<xfs_stats_format+0x3f8>: std r2,24(r1)
<xfs_stats_format+0x3fc>: ld r12,32(r11)
<xfs_stats_format+0x400>: mtctr r12
<xfs_stats_format+0x404>: bctr
<xfs_stats_format+0x408>: .long 0x0
<xfs_stats_format+0x40c>: andi. r20,r27,30050
<xfs_stats_format+0x410>: .long 0xa7c8a0
<xfs_stats_format+0x414>: lfs f0,0(0)
ppc64[6] <xfs_stats_format+0x418>: addis r11,r2,-18
<xfs_stats_format+0x41c>: addi r11,r11,-29808
<xfs_stats_format+0x420>: std r2,24(r1)
<xfs_stats_format+0x424>: ld r12,32(r11)
<xfs_stats_format+0x428>: mtctr r12
<xfs_stats_format+0x42c>: bctr
<xfs_stats_format+0x430>: .long 0x0
<xfs_stats_format+0x434>: andi. r20,r27,30050
<xfs_stats_format+0x438>: .long 0x32fad0
<xfs_stats_format+0x43c>: lfs f0,0(0)
ppc64[7] <xfs_stats_format+0x440>: addis r11,r2,-18
<xfs_stats_format+0x444>: addi r11,r11,-29768
<xfs_stats_format+0x448>: std r2,24(r1)
<xfs_stats_format+0x44c>: ld r12,32(r11)
<xfs_stats_format+0x450>: mtctr r12
<xfs_stats_format+0x454>: bctr
<xfs_stats_format+0x458>: .long 0x0
<xfs_stats_format+0x45c>: andi. r20,r27,30050
<xfs_stats_format+0x460>: .long 0x59a5b0
<xfs_stats_format+0x464>: lfs f0,0(0)
ppc64[8] <xfs_stats_format+0x468>: addis r11,r2,-18
<xfs_stats_format+0x46c>: addi r11,r11,-29728
<xfs_stats_format+0x470>: std r2,24(r1)
<xfs_stats_format+0x474>: ld r12,32(r11)
<xfs_stats_format+0x478>: mtctr r12
<xfs_stats_format+0x47c>: bctr
<xfs_stats_format+0x480>: .long 0x0
<xfs_stats_format+0x484>: andi. r20,r27,30050
<xfs_stats_format+0x488>: .long 0xaabd70
<xfs_stats_format+0x48c>: lfs f0,0(0)
ppc64[9] <xfs_stats_format+0x490>: addis r11,r2,-18
<xfs_stats_format+0x494>: addi r11,r11,-29688
<xfs_stats_format+0x498>: std r2,24(r1)
<xfs_stats_format+0x49c>: ld r12,32(r11)
<xfs_stats_format+0x4a0>: mtctr r12
<xfs_stats_format+0x4a4>: bctr
<xfs_stats_format+0x4a8>: .long 0x0
<xfs_stats_format+0x4ac>: andi. r20,r27,30050
<xfs_stats_format+0x4b0>: .long 0xa55f20
<xfs_stats_format+0x4b4>: lfs f0,0(0)
ppc64[10] <xfs_stats_format+0x4b8>: addis r11,r2,-18
<xfs_stats_format+0x4bc>: addi r11,r11,-29648
<xfs_stats_format+0x4c0>: std r2,24(r1)
<xfs_stats_format+0x4c4>: ld r12,32(r11)
<xfs_stats_format+0x4c8>: mtctr r12
<xfs_stats_format+0x4cc>: bctr
<xfs_stats_format+0x4d0>: .long 0x0
<xfs_stats_format+0x4d4>: andi. r20,r27,30050
<xfs_stats_format+0x4d8>: .long 0x59a730
<xfs_stats_format+0x4dc>: lfs f0,0(0)
ppc64[11] <xfs_stats_format+0x4e0>: addis r11,r2,-18
<xfs_stats_format+0x4e4>: addi r11,r11,-29608
<xfs_stats_format+0x4e8>: std r2,24(r1)
<xfs_stats_format+0x4ec>: ld r12,32(r11)
<xfs_stats_format+0x4f0>: mtctr r12
<xfs_stats_format+0x4f4>: bctr
<xfs_stats_format+0x4f8>: .long 0x0
<xfs_stats_format+0x4fc>: andi. r20,r27,30050
<xfs_stats_format+0x500>: .long 0x1249840
<xfs_stats_format+0x504>: lfs f0,0(0)
ppc64[12] <xfs_stats_format+0x508>: ld r12,16(r13)
<xfs_stats_format+0x50c>: addis r12,r12,-464
<xfs_stats_format+0x510>: addi r12,r12,3568
<xfs_stats_format+0x514>: mtctr r12
<xfs_stats_format+0x518>: bctr
<xfs_stats_format+0x51c>: .long 0x0
<xfs_stats_format+0x520>: .long 0x0
<xfs_stats_format+0x524>: andi. r20,r27,30050
<xfs_stats_format+0x528>: .long 0x78ef0
<xfs_stats_format+0x52c>: lfs f0,0(0)
ppc64[13] <xfs_stats_format+0x530>: ld r12,16(r13)
<xfs_stats_format+0x534>: addis r12,r12,-464
<xfs_stats_format+0x538>: addi r12,r12,3104
<xfs_stats_format+0x53c>: mtctr r12
<xfs_stats_format+0x540>: bctr
<xfs_stats_format+0x544>: .long 0x0
<xfs_stats_format+0x548>: .long 0x0
<xfs_stats_format+0x54c>: andi. r20,r27,30050
<xfs_stats_format+0x550>: .long 0x78d20
<xfs_stats_format+0x554>: lfs f0,0(0)
ppc64[14] ftrace[0] <xfs_stats_format+0x558>: .long 0x0
<xfs_stats_format+0x55c>: .long 0x0
<xfs_stats_format+0x560>: mflr r0
<xfs_stats_format+0x564>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x568>: mtlr r0
<xfs_stats_format+0x56c>: b 0xc0080000099c0014 <patch_free_livepatch+0xc>
ftrace[1] <xfs_stats_format+0x570>: .long 0x0
<xfs_stats_format+0x574>: .long 0x0
<xfs_stats_format+0x578>: mflr r0
<xfs_stats_format+0x57c>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
ppc64[15] <xfs_stats_format+0x580>: mtlr r0
<xfs_stats_format+0x584>: b 0xc0080000099c0100 <patch_free_scaffold+0xc>
ftrace[2] <xfs_stats_format+0x588>: .long 0x0
<xfs_stats_format+0x58c>: .long 0x0
<xfs_stats_format+0x590>: mflr r0
<xfs_stats_format+0x594>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x598>: mtlr r0
<xfs_stats_format+0x59c>: b 0xc0080000099c0244 <patch_find_object_by_name+0xc>
ftrace[3] <xfs_stats_format+0x5a0>: .long 0x0
<xfs_stats_format+0x5a4>: .long 0x0
ppc64[16] <xfs_stats_format+0x5a8>: mflr r0
<xfs_stats_format+0x5ac>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5b0>: mtlr r0
<xfs_stats_format+0x5b4>: b 0xc0080000099c037c <add_callbacks_to_patch_objects+0xc>
ftrace[4] <xfs_stats_format+0x5b8>: .long 0x0
<xfs_stats_format+0x5bc>: .long 0x0
<xfs_stats_format+0x5c0>: mflr r0
<xfs_stats_format+0x5c4>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5c8>: mtlr r0
<xfs_stats_format+0x5cc>: b 0xc0080000099c05ac <init_module+0xc>
ppc64[17] ftrace[5] <xfs_stats_format+0x5d0>: .long 0x0
<xfs_stats_format+0x5d4>: .long 0x0
<xfs_stats_format+0x5d8>: mflr r0
<xfs_stats_format+0x5dc>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
<xfs_stats_format+0x5e0>: mtlr r0
<xfs_stats_format+0x5e4>: b 0xc0080000099c0864 <kpatch_string+0xc>
ftrace[6] <xfs_stats_format+0x5e8>: .long 0x0
<xfs_stats_format+0x5ec>: .long 0x0
<xfs_stats_format+0x5f0>: mflr r0
<xfs_stats_format+0x5f4>: bl 0xc0080000099c0d80 <xfs_stats_format+0x508>
ppc64[18] <xfs_stats_format+0x5f8>: mtlr r0
<xfs_stats_format+0x5fc>: b 0xc0080000099c0884 <xfs_stats_format+0xc>
(unused) <xfs_stats_format+0x600>: .long 0x0
.. <xfs_stats_format+0x604>: .long 0x0
.. <xfs_stats_format+0x608>: .long 0x0
.. <xfs_stats_format+0x60c>: .long 0x0
.. <xfs_stats_format+0x610>: .long 0x0
.. <xfs_stats_format+0x614>: .long 0x0
.. <xfs_stats_format+0x618>: .long 0x0
.. <xfs_stats_format+0x61c>: .long 0x0
ppc64[19] full- <xfs_stats_format+0x620>: addis r11,r2,-18 << klp-relocation
klp-reloc <xfs_stats_format+0x624>: addi r11,r11,-29288 << ppc64_stub_entry
stub[0] <xfs_stats_format+0x628>: std r2,24(r1) << now tacked on *after*
<xfs_stats_format+0x62c>: ld r12,32(r11) << the OOL-ftrace
<xfs_stats_format+0x630>: mtctr r12 << stubs
<xfs_stats_format+0x634>: bctr <<
<xfs_stats_format+0x638>: .long 0x0 <<
<xfs_stats_format+0x63c>: andi. r20,r27,30050 <<
<xfs_stats_format+0x640>: .long 0x54e92b8 <<
<xfs_stats_format+0x644>: lfs f0,0(r8) <<
And finally re-test the original problem, ftrace the livepatch-provided
function:
$ SYSFS=/sys/kernel/debug/tracing
$ echo 0 > $SYSFS/tracing_on
$ echo > $SYSFS/set_ftrace_filter
$ echo function > $SYSFS/current_tracer
$ echo 'xfs_stats_format:mod:livepatch_module' >> $SYSFS/set_ftrace_filter
# Double check the ftrace filter
$ cat $SYSFS/set_ftrace_filter
xfs_stats_format [livepatch_module]
# Bombs away
$ echo 1 > $SYSFS/tracing_on
$ grep kpatch /sys/fs/xfs/stats/stats
kpatch
$ cat $SYSFS/trace
# tracer: function
#
# entries-in-buffer/entries-written: 1/1 #P:8
#
# _-----=> irqs-off/BH-disabled
# / _----=> need-resched
# | / _---=> hardirq/softirq
# || / _--=> preempt-depth
# ||| / _-=> migrate-disable
# |||| / delay
# TASK-PID CPU# ||||| TIMESTAMP FUNCTION
# | | | ||||| | |
grep-71247 [001] ..... 53756.730711: xfs_stats_format <-livepatch_handler
An entry in the trace buffer and no crash :)
--
Joe