Re: [lib] 6ee736dc92: BUG:unable_to_handle_page_fault_for_address

From: Zhaoxiu Zeng
Date: Mon Nov 16 2020 - 12:34:06 EST


在 2020/11/12 14:45, kernel test robot 写道:
>
> Greeting,
>
> FYI, we noticed the following commit (built with gcc-9):
>
> commit: 6ee736dc922a5f81a3a60a72a54ec9392ccfe787 ("[PATCH 2/3] lib: zlib_inflate: improves decompression performance")
> url: https://github.com/0day-ci/linux/commits/zengzhaoxiu-163-com/lib-Introduce-copy_from_back/20201110-033522
> base: https://git.kernel.org/cgit/linux/kernel/git/soc/soc.git for-next
>
> in testcase: nvml
> version: nvml-x86_64-9a558d859-1_20201111
> with following parameters:
>
> test: pmem
> group: util
> nr_pmem: 1
> fs: ext4
> mount_option: dax
> bp_memmap: 32G!4G
> ucode: 0x7000019
>
>
>
> on test machine: 16 threads Intel(R) Xeon(R) CPU D-1541 @ 2.10GHz with 48G memory
>
> caused below changes (please refer to attached dmesg/kmsg for entire log/backtrace):
>
>
> If you fix the issue, kindly add following tag
> Reported-by: kernel test robot <oliver.sang@xxxxxxxxx>
>
>
> [ 5.134501] BUG: unable to handle page fault for address: ffff88880249a4bf
> [ 5.134783] #PF: supervisor read access in kernel mode
> [ 5.134783] #PF: error_code(0x0000) - not-present page
> [ 5.134783] PGD c7f401067 P4D c7f401067 PUD 0
> [ 5.134783] Oops: 0000 [#1] SMP PTI
> [ 5.134783] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 5.10.0-rc1-00071-g6ee736dc922a #1
> [ 5.134783] Hardware name: Supermicro SYS-5018D-FN4T/X10SDV-8C-TLN4F, BIOS 1.1 03/02/2016
> [ 5.134783] RIP: 0010:inflate_fast+0x474/0x600
> [ 5.134783] Code: cc fd ff ff 48 c7 43 30 e5 6d 5a 82 c7 07 1b 00 00 00 e9 ff fc ff ff 48 c7 43 30 cf 6d 5a 82 c7 07 1b 00 00 00 e9 ec fc ff ff <0f> b6 09 48 83 ed 01 49 83 c0 01 41 88 48 ff 48 83 fd 01 76 3f 44
> [ 5.134783] RSP: 0000:ffffc90000047c38 EFLAGS: 00010246
> [ 5.134783] RAX: 000000000000000d RBX: ffff888901886780 RCX: ffff88880249a4bf
> [ 5.134783] RDX: ffffffff0001a4bd RSI: 0000000000000006 RDI: ffff888902490000
> [ 5.134783] RBP: 0000000000000007 R08: ffff888902480002 R09: 0000000000000001
> [ 5.134783] R10: ffff888902490548 R11: ffff888c5af6a3bf R12: 00000000fffe5b43
> [ 5.134783] R13: 0000000000000007 R14: ffff888c7c9ffe23 R15: ffff888902490ef0
> [ 5.134783] FS: 0000000000000000(0000) GS:ffff888c7fa00000(0000) knlGS:0000000000000000
> [ 5.134783] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> [ 5.134783] CR2: ffff88880249a4bf CR3: 0000000c7e20a001 CR4: 00000000003706f0
> [ 5.134783] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
> [ 5.134783] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400
> [ 5.134783] Call Trace:
> [ 5.134783] zlib_inflate+0x99a/0x1780
> [ 5.134783] ? do_copy+0xe3/0x103
> [ 5.134783] ? write_buffer+0x37/0x37
> [ 5.134783] ? initrd_load+0x3f/0x3f
> [ 5.134783] ? write_buffer+0x37/0x37
> [ 5.134783] __gunzip+0x242/0x30c
> [ 5.134783] ? bunzip2+0x39d/0x39d
> [ 5.134783] ? __gunzip+0x30c/0x30c
> [ 5.134783] gunzip+0xe/0x11
> [ 5.134783] ? initrd_load+0x3f/0x3f
> [ 5.134783] unpack_to_rootfs+0x17d/0x2c1
> [ 5.134783] ? initrd_load+0x3f/0x3f
> [ 5.134783] ? do_copy+0x103/0x103
> [ 5.134783] populate_rootfs+0x59/0x109
> [ 5.134783] ? do_copy+0x103/0x103
> [ 5.134783] do_one_initcall+0x44/0x200
> [ 5.134783] kernel_init_freeable+0x1da/0x241
> [ 5.134783] ? rest_init+0xd0/0xd0
> [ 5.134783] kernel_init+0xa/0x110
> [ 5.134783] ret_from_fork+0x22/0x30
> [ 5.134783] Modules linked in:
> [ 5.134783] CR2: ffff88880249a4bf
> [ 5.134783] ---[ end trace a0a85397603c3dac ]---
>
>
> To reproduce:
>
> git clone https://github.com/intel/lkp-tests.git
> cd lkp-tests
> bin/lkp install job.yaml # job file is attached in this email
> bin/lkp run job.yaml
>
>
>
> Thanks,
> Oliver Sang
>

It's not common for copying from the window.
This new patch maybe fix the bug, I build the fedora33's kernel and started it successfully.


Signed-off-by: Zhaoxiu Zeng <zhaoxiu.zeng@xxxxxxxxx>
Reported-by: kernel test robot <oliver.sang@xxxxxxxxx>
---
lib/zlib_inflate/inffast.c | 115 ++++++-------------------------------
1 file changed, 19 insertions(+), 96 deletions(-)

diff --git a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c
index ed1f3df27260..8c9cc928cf71 100644
--- a/lib/zlib_inflate/inffast.c
+++ b/lib/zlib_inflate/inffast.c
@@ -4,29 +4,13 @@
*/

#include <linux/zutil.h>
+#include <asm/copy_from_back.h>
#include "inftrees.h"
#include "inflate.h"
#include "inffast.h"

#ifndef ASMINF

-union uu {
- unsigned short us;
- unsigned char b[2];
-};
-
-/* Endian independed version */
-static inline unsigned short
-get_unaligned16(const unsigned short *p)
-{
- union uu mm;
- unsigned char *b = (unsigned char *)p;
-
- mm.b[0] = b[0];
- mm.b[1] = b[1];
- return mm.us;
-}
-
/*
Decode literal, length, and distance codes and write out the resulting
literal and match bytes until either not enough input or output is
@@ -177,52 +161,34 @@ void inflate_fast(z_streamp strm, unsigned start)
hold >>= op;
bits -= op;
op = (unsigned)(out - beg); /* max distance in output */
- if (dist > op) { /* see if copy from window */
+ if (unlikely(dist > op)) { /* see if copy from window */
op = dist - op; /* distance back in window */
if (op > whave) {
strm->msg = (char *)"invalid distance too far back";
state->mode = BAD;
break;
}
- from = window;
- if (write == 0) { /* very common case */
- from += wsize - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- *out++ = *from++;
- } while (--op);
- from = out - dist; /* rest from output */
- }
- }
- else if (write < op) { /* wrap around window */
- from += wsize + write - op;
- op -= write;
- if (op < len) { /* some from end of window */
- len -= op;
- do {
- *out++ = *from++;
- } while (--op);
- from = window;
- if (write < len) { /* some from start of window */
- op = write;
+ from = window + write - op;
+ if (write < op) { /* very common case */
+ from += wsize;
+ if (write) { /* wrap around window */
+ op -= write;
+ if (op < len) { /* some from end of window */
len -= op;
do {
*out++ = *from++;
} while (--op);
- from = out - dist; /* rest from output */
+ from = window; /* some from start of window */
+ op = write;
}
}
}
- else { /* contiguous in window */
- from += write - op;
- if (op < len) { /* some from window */
- len -= op;
- do {
- *out++ = *from++;
- } while (--op);
- from = out - dist; /* rest from output */
- }
+ if (op < len) { /* some from window */
+ len -= op;
+ do {
+ *out++ = *from++;
+ } while (--op);
+ from = out - dist; /* rest from output */
}
while (len > 2) {
*out++ = *from++;
@@ -235,52 +201,9 @@ void inflate_fast(z_streamp strm, unsigned start)
if (len > 1)
*out++ = *from++;
}
- }
- else {
- unsigned short *sout;
- unsigned long loops;
-
- from = out - dist; /* copy direct from output */
- /* minimum length is three */
- /* Align out addr */
- if (!((long)(out - 1) & 1)) {
- *out++ = *from++;
- len--;
- }
- sout = (unsigned short *)(out);
- if (dist > 2) {
- unsigned short *sfrom;
-
- sfrom = (unsigned short *)(from);
- loops = len >> 1;
- do
-#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
- *sout++ = *sfrom++;
-#else
- *sout++ = get_unaligned16(sfrom++);
-#endif
- while (--loops);
- out = (unsigned char *)sout;
- from = (unsigned char *)sfrom;
- } else { /* dist == 1 or dist == 2 */
- unsigned short pat16;
-
- pat16 = *(sout-1);
- if (dist == 1) {
- union uu mm;
- /* copy one char pattern to both bytes */
- mm.us = pat16;
- mm.b[0] = mm.b[1];
- pat16 = mm.us;
- }
- loops = len >> 1;
- do
- *sout++ = pat16;
- while (--loops);
- out = (unsigned char *)sout;
- }
- if (len & 1)
- *out++ = *from++;
+ } else {
+ /* copy direct from output */
+ out = copy_from_back(out, dist, len);
}
}
else if ((op & 64) == 0) { /* 2nd level distance code */
--
2.28.0