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 Original line Diff line number Diff line
@@ -526,6 +526,7 @@ config CRASH_DUMP
	bool "kernel crash dumps"
	bool "kernel crash dumps"
	depends on 64BIT && SMP
	depends on 64BIT && SMP
	select KEXEC
	select KEXEC
	select ZFCPDUMP
	help
	help
	  Generate crash dump after being started by kexec.
	  Generate crash dump after being started by kexec.
	  Crash dump kernels are loaded in the main kernel with kexec-tools
	  Crash dump kernels are loaded in the main kernel with kexec-tools
@@ -536,7 +537,7 @@ config CRASH_DUMP
config ZFCPDUMP
config ZFCPDUMP
	def_bool n
	def_bool n
	prompt "zfcpdump support"
	prompt "zfcpdump support"
	select SMP
	depends on SMP
	help
	help
	  Select this option if you want to build an zfcpdump enabled kernel.
	  Select this option if you want to build an zfcpdump enabled kernel.
	  Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
	  Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
+1 −0
Original line number Original line Diff line number Diff line
@@ -56,5 +56,6 @@ bool sclp_has_linemode(void);
bool sclp_has_vt220(void);
bool sclp_has_vt220(void);
int sclp_pci_configure(u32 fid);
int sclp_pci_configure(u32 fid);
int sclp_pci_deconfigure(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 */
#endif /* _ASM_S390_SCLP_H */
+104 −18
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#include <asm/os_info.h>
#include <asm/os_info.h>
#include <asm/elf.h>
#include <asm/elf.h>
#include <asm/ipl.h>
#include <asm/ipl.h>
#include <asm/sclp.h>


#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_ADD(x, y) (((char *) (x)) + ((unsigned long) (y)))
#define PTR_SUB(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;
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:
 * For the kdump reserved memory this functions performs a swap operation:
 *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
 *  - [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE] is mapped to [0 - OLDMEM_SIZE].
 *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 *  - [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 */
 */
ssize_t copy_oldmem_page(unsigned long pfn, char *buf,
static ssize_t copy_oldmem_page_kdump(char *buf, size_t csize,
			 size_t csize, unsigned long offset, int userbuf)
				      unsigned long src, int userbuf)

{
{
	unsigned long src;
	int rc;
	int rc;


	if (!csize)
		return 0;

	src = (pfn << PAGE_SHIFT) + offset;
	if (src < OLDMEM_SIZE)
	if (src < OLDMEM_SIZE)
		src += OLDMEM_BASE;
		src += OLDMEM_BASE;
	else if (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);
				       (void *) src, csize);
	else
	else
		rc = copy_page_real(buf, (void *) src, csize);
		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:
 * For the kdump reserved memory this functions performs a swap operation:
 * [0 - OLDMEM_SIZE] is mapped to [OLDMEM_BASE - OLDMEM_BASE + OLDMEM_SIZE]
 * [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,
static int remap_oldmem_pfn_range_kdump(struct vm_area_struct *vma,
			   unsigned long pfn, unsigned long size, pgprot_t prot)
					unsigned long from, unsigned long pfn,
					unsigned long size, pgprot_t prot)
{
{
	unsigned long size_old;
	unsigned long size_old;
	int rc;
	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);
	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
 * Copy memory from old kernel
 */
 */
@@ -132,12 +207,22 @@ int copy_from_oldmem(void *dest, void *src, size_t count)
	unsigned long copied = 0;
	unsigned long copied = 0;
	int rc;
	int rc;


	if (OLDMEM_BASE) {
		if ((unsigned long) src < OLDMEM_SIZE) {
		if ((unsigned long) src < OLDMEM_SIZE) {
			copied = min(count, OLDMEM_SIZE - (unsigned long) src);
			copied = min(count, OLDMEM_SIZE - (unsigned long) src);
			rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
			rc = memcpy_real(dest, src + OLDMEM_BASE, copied);
			if (rc)
			if (rc)
				return 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);
	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;
	u32 alloc_size;
	u64 hdr_off;
	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;
		return 0;
	/* If elfcorehdr= has been passed via cmdline, we use that one */
	/* If elfcorehdr= has been passed via cmdline, we use that one */
	if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
	if (elfcorehdr_addr != ELFCORE_ADDR_MAX)
+3 −3
Original line number Original line Diff line number Diff line
@@ -30,8 +30,8 @@


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


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


enum arch_id {
enum arch_id {
@@ -73,7 +73,7 @@ static struct ipl_parameter_block *ipl_block;
 * @count: Size of buffer, which should be copied
 * @count: Size of buffer, which should be copied
 * @mode:  Either TO_KERNEL or TO_USER
 * @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;
	int offs, blk_num;
	static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));
	static char buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE)));