Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6f79d332 authored by Michael Holzheu's avatar Michael Holzheu Committed by Linus Torvalds
Browse files

s390/vmcore: use vmcore for zfcpdump



Modify the s390 copy_oldmem_page() and remap_oldmem_pfn_range() function
for zfcpdump to read from the HSA memory if memory below HSA_SIZE bytes is
requested.  Otherwise real memory is used.

Signed-off-by: default avatarMichael Holzheu <holzheu@linux.vnet.ibm.com>
Cc: HATAYAMA Daisuke <d.hatayama@jp.fujitsu.com>
Cc: Jan Willeke <willeke@de.ibm.com>
Cc: Vivek Goyal <vgoyal@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 11e376a3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -526,6 +526,7 @@ config CRASH_DUMP
	bool "kernel crash dumps"
	depends on 64BIT && SMP
	select KEXEC
	select ZFCPDUMP
	help
	  Generate crash dump after being started by kexec.
	  Crash dump kernels are loaded in the main kernel with kexec-tools
@@ -536,7 +537,7 @@ config CRASH_DUMP
config ZFCPDUMP
	def_bool n
	prompt "zfcpdump support"
	select SMP
	depends on SMP
	help
	  Select this option if you want to build an zfcpdump enabled kernel.
	  Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+1 −0
Original line number Diff line number Diff line
@@ -56,5 +56,6 @@ bool sclp_has_linemode(void);
bool sclp_has_vt220(void);
int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(u32 fid);
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);

#endif /* _ASM_S390_SCLP_H */
+104 −18
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@
#include <asm/os_info.h>
#include <asm/elf.h>
#include <asm/ipl.h>
#include <asm/sclp.h>

#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_SUB(x, y) (((char *) (x)) - ((unsigned long) (y)))
@@ -69,22 +70,41 @@ static ssize_t copy_page_real(void *buf, void *src, size_t csize)
static void *elfcorehdr_newmem;

/*
 * Copy one page from "oldmem"
 * Copy one page from zfcpdump "oldmem"
 *
 * For pages below ZFCPDUMP_HSA_SIZE memory from the HSA is copied. Otherwise
 * real memory copy is used.
 */
static ssize_t copy_oldmem_page_zfcpdump(char *buf, size_t csize,
					 unsigned long src, int userbuf)
{
	int rc;

	if (src < ZFCPDUMP_HSA_SIZE) {
		rc = memcpy_hsa(buf, src, csize, userbuf);
	} else {
		if (userbuf)
			rc = copy_to_user_real((void __force __user *) buf,
					       (void *) src, csize);
		else
			rc = memcpy_real(buf, (void *) src, csize);
	}
	return rc ? rc : csize;
}

/*
 * Copy one page from kdump "oldmem"
 *
 * For the kdump reserved memory this functions performs a swap operation:
 *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
 *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 */
ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
			 size_t csize, unsigned long offset, int userbuf)
static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
				      unsigned long src, int userbuf)

{
	unsigned long src;
	int rc;

	if (!csize)
		return 0;

	src = (pfn << PAGE_SHIFT) + offset;
	if (src < OLDMEM_SIZE)
		src += OLDMEM_BASE;
	else if (src > OLDMEM_BASE &&
@@ -95,17 +115,35 @@ ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
				       (void *) src, csize);
	else
		rc = copy_page_real(buf, (void *) src, csize);
	return (rc == 0) ? csize : rc;
	return (rc == 0) ? rc : csize;
}

/*
 * Copy one page from "oldmem"
 */
ssize_t copy_oldmem_page(unsigned long pfn, char *buf, size_t csize,
			 unsigned long offset, int userbuf)
{
	unsigned long src;

	if (!csize)
		return 0;
	src = (pfn << PAGE_SHIFT) + offset;
	if (OLDMEM_BASE)
		return copy_oldmem_page_kdump(buf, csize, src, userbuf);
	else
		return copy_oldmem_page_zfcpdump(buf, csize, src, userbuf);
}

/*
 * Remap "oldmem"
 * Remap "oldmem" for kdump
 *
 * For the kdump reserved memory this functions performs a swap operation:
 * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 */
int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
			   unsigned long pfn, unsigned long size, pgprot_t prot)
static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
					unsigned long from, unsigned long pfn,
					unsigned long size, pgprot_t prot)
{
	unsigned long size_old;
	int rc;
@@ -124,6 +162,43 @@ int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
	return remap_pfn_range(vma, from, pfn, size, prot);
}

/*
 * Remap "oldmem" for zfcpdump
 *
 * We only map available memory above ZFCPDUMP_HSA_SIZE. Memory below
 * ZFCPDUMP_HSA_SIZE is read on demand using the copy_oldmem_page() function.
 */
static int remap_oldmem_pfn_range_zfcpdump(struct vm_area_struct *vma,
					   unsigned long from,
					   unsigned long pfn,
					   unsigned long size, pgprot_t prot)
{
	unsigned long size_hsa;

	if (pfn < ZFCPDUMP_HSA_SIZE >> PAGE_SHIFT) {
		size_hsa = min(size, ZFCPDUMP_HSA_SIZE - (pfn << PAGE_SHIFT));
		if (size == size_hsa)
			return 0;
		size -= size_hsa;
		from += size_hsa;
		pfn += size_hsa >> PAGE_SHIFT;
	}
	return remap_pfn_range(vma, from, pfn, size, prot);
}

/*
 * Remap "oldmem" for kdump or zfcpdump
 */
int remap_oldmem_pfn_range(struct vm_area_struct *vma, unsigned long from,
			   unsigned long pfn, unsigned long size, pgprot_t prot)
{
	if (OLDMEM_BASE)
		return remap_oldmem_pfn_range_kdump(vma, from, pfn, size, prot);
	else
		return remap_oldmem_pfn_range_zfcpdump(vma, from, pfn, size,
						       prot);
}

/*
 * Copy memory from old kernel
 */
@@ -132,12 +207,22 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
	unsigned long copied = 0;
	int rc;

	if (OLDMEM_BASE) {
		if ((unsigned long) src < OLDMEM_SIZE) {
			copied = min(count, OLDMEM_SIZE - (unsigned long) src);
			rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
			if (rc)
				return rc;
		}
	} else {
		if ((unsigned long) src < ZFCPDUMP_HSA_SIZE) {
			copied = min(count,
				     ZFCPDUMP_HSA_SIZE - (unsigned long) src);
			rc = memcpy_hsa(dest, (unsigned long) src, copied, 0);
			if (rc)
				return rc;
		}
	}
	return memcpy_real(dest + copied, src + copied, count - copied);
}

@@ -466,7 +551,8 @@ int elfcorehdr_alloc(unsigned long long *addr, unsigned long long *size)
	u32 alloc_size;
	u64 hdr_off;

	if (!OLDMEM_BASE)
	/* If we are not in kdump or zfcpdump mode return */
	if (!OLDMEM_BASE && ipl_info.type != IPL_TYPE_FCP_DUMP)
		return 0;
	/* If elfcorehdr= has been passed via cmdline, we use that one */
	if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
+3 −3
Original line number Diff line number Diff line
@@ -30,8 +30,8 @@

#define TRACE(x...) debug_sprintf_event(zcore_dbf, 1, x)

#define TO_USER		0
#define TO_KERNEL	1
#define TO_USER		1
#define TO_KERNEL	0
#define CHUNK_INFO_SIZE	34 /* 2 16-byte char, each followed by blank */

enum arch_id {
@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block;
 * @count: Size of buffer, which should be copied
 * @mode:  Either TO_KERNEL or TO_USER
 */
static int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode)
{
	int offs, blk_num;
	static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));