Skip to content

Commit 191a2fa

Browse files
Michael HolzheuMartin Schwidefsky
authored andcommitted
s390/kdump: Allow copy_oldmem_page() copy to virtual memory
The kdump mmap patch series (git commit 8308697) changed the requirements for copy_oldmem_page(). Now this function is used for copying to virtual memory. So implement vmalloc support for the s390 version of copy_oldmem_page(). Signed-off-by: Michael Holzheu <[email protected]> Signed-off-by: Martin Schwidefsky <[email protected]>
1 parent 5a74953 commit 191a2fa

File tree

1 file changed

+47
-4
lines changed

1 file changed

+47
-4
lines changed

arch/s390/kernel/crash_dump.c

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,48 @@
2121
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
2222
#define PTR_DIFF(x, y) ((unsigned long)(((char *) (x)) - ((unsigned long) (y))))
2323

24+
25+
/*
26+
* Return physical address for virtual address
27+
*/
28+
static inline void *load_real_addr(void *addr)
29+
{
30+
unsigned long real_addr;
31+
32+
asm volatile(
33+
" lra %0,0(%1)\n"
34+
" jz 0f\n"
35+
" la %0,0\n"
36+
"0:"
37+
: "=a" (real_addr) : "a" (addr) : "cc");
38+
return (void *)real_addr;
39+
}
40+
41+
/*
42+
* Copy up to one page to vmalloc or real memory
43+
*/
44+
static ssize_t copy_page_real(void *buf, void *src, size_t csize)
45+
{
46+
size_t size;
47+
48+
if (is_vmalloc_addr(buf)) {
49+
BUG_ON(csize >= PAGE_SIZE);
50+
/* If buf is not page aligned, copy first part */
51+
size = min(roundup(__pa(buf), PAGE_SIZE) - __pa(buf), csize);
52+
if (size) {
53+
if (memcpy_real(load_real_addr(buf), src, size))
54+
return -EFAULT;
55+
buf += size;
56+
src += size;
57+
}
58+
/* Copy second part */
59+
size = csize - size;
60+
return (size) ? memcpy_real(load_real_addr(buf), src, size) : 0;
61+
} else {
62+
return memcpy_real(buf, src, csize);
63+
}
64+
}
65+
2466
/*
2567
* Copy one page from "oldmem"
2668
*
@@ -32,6 +74,7 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
3274
size_t csize, unsigned long offset, int userbuf)
3375
{
3476
unsigned long src;
77+
int rc;
3578

3679
if (!csize)
3780
return 0;
@@ -43,11 +86,11 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
4386
src < OLDMEM_BASE + OLDMEM_SIZE)
4487
src -= OLDMEM_BASE;
4588
if (userbuf)
46-
copy_to_user_real((void __force __user *) buf, (void *) src,
47-
csize);
89+
rc = copy_to_user_real((void __force __user *) buf,
90+
(void *) src, csize);
4891
else
49-
memcpy_real(buf, (void *) src, csize);
50-
return csize;
92+
rc = copy_page_real(buf, (void *) src, csize);
93+
return (rc == 0) ? csize : rc;
5194
}
5295

5396
/*

0 commit comments

Comments
 (0)