s390/zcore: remove /sys/kernel/debug/zcore/mem

New versions of the SCSI dumper use the /dev/vmcore interface instead
of zcore mem. Remove the outdated interface.

Acked-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Martin Schwidefsky 2015-10-28 09:47:58 +01:00
parent bbfed511c2
commit ffa52d02c5
4 changed files with 17 additions and 402 deletions

View File

@ -15,19 +15,15 @@ the s390-tools package) to make the device bootable. The operator of a Linux
system can then trigger a SCSI dump by booting the SCSI disk, where zfcpdump
resides on.
The kernel part of zfcpdump is implemented as a debugfs file under "zcore/mem",
which exports memory and registers of the crashed Linux in an s390
standalone dump format. It can be used in the same way as e.g. /dev/mem. The
dump format defines a 4K header followed by plain uncompressed memory. The
register sets are stored in the prefix pages of the respective CPUs. To build a
dump enabled kernel with the zcore driver, the kernel config option
CONFIG_CRASH_DUMP has to be set. When reading from "zcore/mem", the part of
memory, which has been saved by hardware is read by the driver via the SCLP
hardware interface. The second part is just copied from the non overwritten real
memory.
The user space dump tool accesses the memory of the crashed system by means
of the /proc/vmcore interface. This interface exports the crashed system's
memory and registers in ELF core dump format. To access the memory which has
been saved by the hardware SCLP requests will be created at the time the data
is needed by /proc/vmcore. The tail part of the crashed systems memory which
has not been stashed by hardware can just be copied from real memory.
Since kernel version 3.12 also the /proc/vmcore file can also be used to access
the dump.
To build a dump enabled kernel the kernel config option CONFIG_CRASH_DUMP
has to be set.
To get a valid zfcpdump kernel configuration use "make zfcpdump_defconfig".

View File

@ -35,7 +35,6 @@ struct save_area {
struct save_area_ext {
struct save_area sa;
__vector128 vx_regs[32];
u64 vx_sa_addr;
};
struct _lowcore {

View File

@ -30,9 +30,7 @@ obj-$(CONFIG_S390_TAPE_3590) += tape_3590.o
obj-$(CONFIG_MONREADER) += monreader.o
obj-$(CONFIG_MONWRITER) += monwriter.o
obj-$(CONFIG_S390_VMUR) += vmur.o
zcore_mod-objs := sclp_sdias.o zcore.o
obj-$(CONFIG_CRASH_DUMP) += zcore_mod.o
obj-$(CONFIG_CRASH_DUMP) += sclp_sdias.o zcore.o
hmcdrv-objs := hmcdrv_mod.o hmcdrv_dev.o hmcdrv_ftp.o hmcdrv_cache.o diag_ftp.o sclp_ftp.o
obj-$(CONFIG_HMC_DRV) += hmcdrv.o

View File

@ -43,27 +43,14 @@ enum arch_id {
ARCH_S390X = 1,
};
/* dump system info */
struct sys_info {
enum arch_id arch;
unsigned long sa_base;
u32 sa_size;
int cpu_map[NR_CPUS];
unsigned long mem_size;
struct save_area lc_mask;
};
struct ipib_info {
unsigned long ipib;
u32 checksum;
} __attribute__((packed));
static struct sys_info sys_info;
static struct debug_info *zcore_dbf;
static int hsa_available;
static struct dentry *zcore_dir;
static struct dentry *zcore_file;
static struct dentry *zcore_memmap_file;
static struct dentry *zcore_reipl_file;
static struct dentry *zcore_hsa_file;
@ -149,171 +136,22 @@ static int memcpy_hsa_kernel(void *dest, unsigned long src, size_t count)
return memcpy_hsa(dest, src, count, TO_KERNEL);
}
static int __init init_cpu_info(enum arch_id arch)
static int __init init_cpu_info(void)
{
struct save_area_ext *sa_ext;
struct _lowcore *lc;
void *ptr;
int i;
/* get info for boot cpu from lowcore, stored in the HSA */
sa_ext = dump_save_areas.areas[0];
if (!sa_ext)
return -ENOMEM;
if (memcpy_hsa_kernel(&sa_ext->sa, sys_info.sa_base,
sys_info.sa_size) < 0) {
if (memcpy_hsa_kernel(&sa_ext->sa, SAVE_AREA_BASE,
sizeof(struct save_area)) < 0) {
TRACE("could not copy from HSA\n");
return -EIO;
}
if (!MACHINE_HAS_VX)
return 0;
save_vx_regs_safe(sa_ext->vx_regs);
/* Get address of the vector register save area for each CPU */
for (i = 0; i < dump_save_areas.count; i++) {
sa_ext = dump_save_areas.areas[i];
lc = (struct _lowcore *)(unsigned long) sa_ext->sa.pref_reg;
ptr = &lc->vector_save_area_addr;
copy_from_oldmem(&sa_ext->vx_sa_addr, ptr,
sizeof(sa_ext->vx_sa_addr));
}
return 0;
}
static DEFINE_MUTEX(zcore_mutex);
#define DUMP_VERSION 0x5
#define DUMP_MAGIC 0xa8190173618f23fdULL
#define DUMP_ARCH_S390X 2
#define DUMP_ARCH_S390 1
#define HEADER_SIZE 4096
/* dump header dumped according to s390 crash dump format */
struct zcore_header {
u64 magic;
u32 version;
u32 header_size;
u32 dump_level;
u32 page_size;
u64 mem_size;
u64 mem_start;
u64 mem_end;
u32 num_pages;
u32 pad1;
u64 tod;
struct cpuid cpu_id;
u32 arch_id;
u32 volnr;
u32 build_arch;
u64 rmem_size;
u8 mvdump;
u16 cpu_cnt;
u16 real_cpu_cnt;
u8 end_pad1[0x200-0x061];
u64 mvdump_sign;
u64 mvdump_zipl_time;
u8 end_pad2[0x800-0x210];
u32 lc_vec[512];
} __attribute__((packed,__aligned__(16)));
static struct zcore_header zcore_header = {
.magic = DUMP_MAGIC,
.version = DUMP_VERSION,
.header_size = 4096,
.dump_level = 0,
.page_size = PAGE_SIZE,
.mem_start = 0,
.build_arch = DUMP_ARCH_S390X,
};
/*
* Copy lowcore info to buffer. Use map in order to copy only register parts.
*
* @buf: User buffer
* @sa: Pointer to save area
* @sa_off: Offset in save area to copy
* @len: Number of bytes to copy
*/
static int copy_lc(void __user *buf, void *sa, int sa_off, int len)
{
int i;
char *lc_mask = (char*)&sys_info.lc_mask;
for (i = 0; i < len; i++) {
if (!lc_mask[i + sa_off])
continue;
if (copy_to_user(buf + i, sa + sa_off + i, 1))
return -EFAULT;
}
return 0;
}
/*
* Copy lowcores info to memory, if necessary
*
* @buf: User buffer
* @addr: Start address of buffer in dump memory
* @count: Size of buffer
*/
static int zcore_add_lc(char __user *buf, unsigned long start, size_t count)
{
struct save_area_ext *sa_ext;
struct save_area *sa;
unsigned long end;
int i;
if (count == 0)
return 0;
end = start + count;
for (i = 0; i < dump_save_areas.count; i++) {
unsigned long cp_start, cp_end; /* copy range */
unsigned long sa_start, sa_end; /* save area range */
unsigned long sa_off, len, buf_off;
sa_ext = dump_save_areas.areas[i];
sa = &sa_ext->sa;
/* Copy the 512 bytes lowcore save area 0x1200 - 0x1400 */
sa_start = sa->pref_reg + sys_info.sa_base;
sa_end = sa_start + sys_info.sa_size;
if (end >= sa_start && start < sa_end) {
cp_start = max(start, sa_start);
cp_end = min(end, sa_end);
buf_off = cp_start - start;
sa_off = cp_start - sa_start;
len = cp_end - cp_start;
TRACE("copy_lc: %lx-%lx\n", cp_start, cp_end);
if (copy_lc(buf + buf_off, sa, sa_off, len))
return -EFAULT;
}
if (!MACHINE_HAS_VX)
continue;
/* Copy the 512 bytes vector save area */
sa_start = sa_ext->vx_sa_addr & -1024UL;
sa_end = sa_start + 512;
if (end >= sa_start && start < sa_end) {
cp_start = max(start, sa_start);
cp_end = min(end, sa_end);
buf_off = cp_start - start;
sa_off = cp_start - sa_start;
len = cp_end - cp_start;
TRACE("copy vxrs: %lx-%lx\n", cp_start, cp_end);
if (copy_to_user(buf + buf_off,
(void *) &sa_ext->vx_regs + sa_off,
len))
return -EFAULT;
}
}
if (MACHINE_HAS_VX)
save_vx_regs_safe(sa_ext->vx_regs);
return 0;
}
@ -326,126 +164,6 @@ static void release_hsa(void)
hsa_available = 0;
}
/*
* Read routine for zcore character device
* First 4K are dump header
* Next 32MB are HSA Memory
* Rest is read from absolute Memory
*/
static ssize_t zcore_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
unsigned long mem_start; /* Start address in memory */
size_t mem_offs; /* Offset in dump memory */
size_t hdr_count; /* Size of header part of output buffer */
size_t size;
int rc;
mutex_lock(&zcore_mutex);
if (*ppos > (sys_info.mem_size + HEADER_SIZE)) {
rc = -EINVAL;
goto fail;
}
count = min(count, (size_t) (sys_info.mem_size + HEADER_SIZE - *ppos));
/* Copy dump header */
if (*ppos < HEADER_SIZE) {
size = min(count, (size_t) (HEADER_SIZE - *ppos));
if (copy_to_user(buf, &zcore_header + *ppos, size)) {
rc = -EFAULT;
goto fail;
}
hdr_count = size;
mem_start = 0;
} else {
hdr_count = 0;
mem_start = *ppos - HEADER_SIZE;
}
mem_offs = 0;
/* Copy from HSA data */
if (*ppos < sclp.hsa_size + HEADER_SIZE) {
size = min((count - hdr_count),
(size_t) (sclp.hsa_size - mem_start));
rc = memcpy_hsa_user(buf + hdr_count, mem_start, size);
if (rc)
goto fail;
mem_offs += size;
}
/* Copy from real mem */
size = count - mem_offs - hdr_count;
rc = copy_to_user_real(buf + hdr_count + mem_offs,
(void *) mem_start + mem_offs, size);
if (rc)
goto fail;
/*
* Since s390 dump analysis tools like lcrash or crash
* expect register sets in the prefix pages of the cpus,
* we copy them into the read buffer, if necessary.
* buf + hdr_count: Start of memory part of output buffer
* mem_start: Start memory address to copy from
* count - hdr_count: Size of memory area to copy
*/
if (zcore_add_lc(buf + hdr_count, mem_start, count - hdr_count)) {
rc = -EFAULT;
goto fail;
}
*ppos += count;
fail:
mutex_unlock(&zcore_mutex);
return (rc < 0) ? rc : count;
}
static int zcore_open(struct inode *inode, struct file *filp)
{
if (!hsa_available)
return -ENODATA;
else
return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
}
static int zcore_release(struct inode *inode, struct file *filep)
{
if (hsa_available)
release_hsa();
return 0;
}
static loff_t zcore_lseek(struct file *file, loff_t offset, int orig)
{
loff_t rc;
mutex_lock(&zcore_mutex);
switch (orig) {
case 0:
file->f_pos = offset;
rc = file->f_pos;
break;
case 1:
file->f_pos += offset;
rc = file->f_pos;
break;
default:
rc = -EINVAL;
}
mutex_unlock(&zcore_mutex);
return rc;
}
static const struct file_operations zcore_fops = {
.owner = THIS_MODULE,
.llseek = zcore_lseek,
.read = zcore_read,
.open = zcore_open,
.release = zcore_release,
};
static ssize_t zcore_memmap_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
@ -549,50 +267,6 @@ static const struct file_operations zcore_hsa_fops = {
.llseek = no_llseek,
};
static void __init set_lc_mask(struct save_area *map)
{
memset(&map->fp_regs, 0xff, sizeof(map->fp_regs));
memset(&map->gp_regs, 0xff, sizeof(map->gp_regs));
memset(&map->psw, 0xff, sizeof(map->psw));
memset(&map->pref_reg, 0xff, sizeof(map->pref_reg));
memset(&map->fp_ctrl_reg, 0xff, sizeof(map->fp_ctrl_reg));
memset(&map->tod_reg, 0xff, sizeof(map->tod_reg));
memset(&map->timer, 0xff, sizeof(map->timer));
memset(&map->clk_cmp, 0xff, sizeof(map->clk_cmp));
memset(&map->acc_regs, 0xff, sizeof(map->acc_regs));
memset(&map->ctrl_regs, 0xff, sizeof(map->ctrl_regs));
}
/*
* Initialize dump globals for a given architecture
*/
static int __init sys_info_init(enum arch_id arch, unsigned long mem_end)
{
int rc;
switch (arch) {
case ARCH_S390X:
pr_alert("DETECTED 'S390X (64 bit) OS'\n");
break;
case ARCH_S390:
pr_alert("DETECTED 'S390 (32 bit) OS'\n");
break;
default:
pr_alert("0x%x is an unknown architecture.\n",arch);
return -EINVAL;
}
sys_info.sa_base = SAVE_AREA_BASE;
sys_info.sa_size = sizeof(struct save_area);
sys_info.arch = arch;
set_lc_mask(&sys_info.lc_mask);
rc = init_cpu_info(arch);
if (rc)
return rc;
sys_info.mem_size = mem_end;
return 0;
}
static int __init check_sdias(void)
{
if (!sclp.hsa_size) {
@ -602,43 +276,6 @@ static int __init check_sdias(void)
return 0;
}
static int __init get_mem_info(unsigned long *mem, unsigned long *end)
{
struct memblock_region *reg;
for_each_memblock(memory, reg) {
*mem += reg->size;
*end = max_t(unsigned long, *end, reg->base + reg->size);
}
return 0;
}
static void __init zcore_header_init(int arch, struct zcore_header *hdr,
unsigned long mem_size)
{
u32 prefix;
int i;
if (arch == ARCH_S390X)
hdr->arch_id = DUMP_ARCH_S390X;
else
hdr->arch_id = DUMP_ARCH_S390;
hdr->mem_size = mem_size;
hdr->rmem_size = mem_size;
hdr->mem_end = sys_info.mem_size;
hdr->num_pages = mem_size / PAGE_SIZE;
hdr->tod = get_tod_clock();
get_cpu_id(&hdr->cpu_id);
for (i = 0; i < dump_save_areas.count; i++) {
prefix = dump_save_areas.areas[i]->sa.pref_reg;
hdr->real_cpu_cnt++;
if (!prefix)
continue;
hdr->lc_vec[hdr->cpu_cnt] = prefix;
hdr->cpu_cnt++;
}
}
/*
* Provide IPL parameter information block from either HSA or memory
* for future reipl
@ -671,11 +308,9 @@ static int __init zcore_reipl_init(void)
static int __init zcore_init(void)
{
unsigned long mem_size, mem_end;
unsigned char arch;
int rc;
mem_size = mem_end = 0;
if (ipl_info.type != IPL_TYPE_FCP_DUMP)
return -ENODATA;
if (OLDMEM_BASE)
@ -709,15 +344,11 @@ static int __init zcore_init(void)
goto fail;
}
rc = get_mem_info(&mem_size, &mem_end);
pr_alert("DETECTED 'S390X (64 bit) OS'\n");
rc = init_cpu_info();
if (rc)
goto fail;
rc = sys_info_init(arch, mem_end);
if (rc)
goto fail;
zcore_header_init(arch, &zcore_header, mem_size);
rc = zcore_reipl_init();
if (rc)
goto fail;
@ -727,17 +358,11 @@ static int __init zcore_init(void)
rc = -ENOMEM;
goto fail;
}
zcore_file = debugfs_create_file("mem", S_IRUSR, zcore_dir, NULL,
&zcore_fops);
if (!zcore_file) {
rc = -ENOMEM;
goto fail_dir;
}
zcore_memmap_file = debugfs_create_file("memmap", S_IRUSR, zcore_dir,
NULL, &zcore_memmap_fops);
if (!zcore_memmap_file) {
rc = -ENOMEM;
goto fail_file;
goto fail_dir;
}
zcore_reipl_file = debugfs_create_file("reipl", S_IRUSR, zcore_dir,
NULL, &zcore_reipl_fops);
@ -757,8 +382,6 @@ static int __init zcore_init(void)
debugfs_remove(zcore_reipl_file);
fail_memmap_file:
debugfs_remove(zcore_memmap_file);
fail_file:
debugfs_remove(zcore_file);
fail_dir:
debugfs_remove(zcore_dir);
fail:
@ -774,7 +397,6 @@ static void __exit zcore_exit(void)
debugfs_remove(zcore_hsa_file);
debugfs_remove(zcore_reipl_file);
debugfs_remove(zcore_memmap_file);
debugfs_remove(zcore_file);
debugfs_remove(zcore_dir);
diag308(DIAG308_REL_HSA, NULL);
}