Files
s390-tools/hsavmcore/hsa.c
Alexander Egorenkov 8c9cc6e12a s390-tools: add hsavmcore utility
hsavmcore is designed to make the dump process with kdump more efficient.
With hsavmcore, the HSA memory that contains a part of the production
kernel's memory can be released early in the process. Depending on the size
of the production kernel's memory, writing the dump to persistent storage
can be time consuming and prevent the HSA memory from being reused
by other LPARs.

Signed-off-by: Alexander Egorenkov <egorenar@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Acked-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
2021-06-18 13:20:08 +02:00

173 lines
4.0 KiB
C

/*
* Copyright IBM Corp. 2021
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <elf.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "lib/util_file.h"
#include "lib/util_log.h"
#include "hsa.h"
long get_hsa_size(const char *zcore_hsa_path)
{
long size;
int ret;
util_log_print(UTIL_LOG_DEBUG, "Reading HSA memory size from %s\n",
zcore_hsa_path);
/* Read HSA size */
ret = util_file_read_l(&size, 16, zcore_hsa_path);
if (ret < 0) {
util_log_print(UTIL_LOG_ERROR, "File read failed (%s)\n",
strerror(errno));
return -1;
}
return size;
}
long get_hsa_vmcore_offset(const char *vmcore_path)
{
Elf64_Ehdr elf_hdr;
int fd = -1, n, i;
long offset = -1;
util_log_print(UTIL_LOG_DEBUG,
"Reading HSA memory offset from vmcore %s\n",
vmcore_path);
/* Open vmcore file */
fd = open(vmcore_path, O_RDONLY);
if (fd < 0) {
util_log_print(UTIL_LOG_ERROR, "open syscall failed (%s)\n",
strerror(errno));
goto fail;
}
util_log_print(UTIL_LOG_DEBUG, "Reading vmcore ELF header\n");
/* Read ELF header */
n = read(fd, &elf_hdr, sizeof(Elf64_Ehdr));
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n != sizeof(Elf64_Ehdr)) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected (%s)\n",
strerror(errno));
goto fail;
}
/* Verify ELF header */
if ((memcmp(elf_hdr.e_ident, ELFMAG, SELFMAG) != 0) ||
elf_hdr.e_type != ET_CORE || elf_hdr.e_machine != EM_S390 ||
elf_hdr.e_ident[EI_CLASS] != ELFCLASS64) {
util_log_print(UTIL_LOG_ERROR, "Invalid vmcore ELF header\n");
goto fail;
}
util_log_print(UTIL_LOG_DEBUG,
"Reading vmcore ELF program header(s)\n");
/* Read ELF program header(s) */
n = lseek(fd, elf_hdr.e_phoff, SEEK_SET);
if (n < 0) {
util_log_print(UTIL_LOG_ERROR, "lseek syscall failed (%s)\n",
strerror(errno));
goto fail;
}
/*
* Go through all ELF program headers and find one
* that starts at physical/virtual address 0x0.
*/
for (i = 0; i < elf_hdr.e_phnum; i++) {
Elf64_Phdr elf_phdr;
util_log_print(UTIL_LOG_DEBUG,
"Reading vmcore ELF program header #%d\n", i);
n = read(fd, &elf_phdr, sizeof(Elf64_Phdr));
if (n < 0) {
util_log_print(UTIL_LOG_ERROR,
"read syscall failed (%s)\n",
strerror(errno));
goto fail;
} else if (n != sizeof(Elf64_Phdr)) {
util_log_print(UTIL_LOG_ERROR,
"read syscall read less data than expected (%s)\n",
strerror(errno));
goto fail;
}
util_log_print(UTIL_LOG_DEBUG,
"vmcore ELF program segment #%d: type=%lx vaddr=%lx paddr=%lx offset=%lx\n",
i, elf_phdr.p_type, elf_phdr.p_vaddr,
elf_phdr.p_paddr, elf_phdr.p_offset);
/* HSA memory starts at physical/virtual address 0x0 */
if (elf_phdr.p_type == PT_LOAD && elf_phdr.p_vaddr == 0 &&
elf_phdr.p_paddr == 0) {
offset = elf_phdr.p_offset;
break;
}
}
if (offset < 0) {
util_log_print(UTIL_LOG_ERROR,
"Couldn't find HSA memory offset in vmcore\n");
goto fail;
}
util_log_print(UTIL_LOG_DEBUG, "HSA memory vmcore offset %lx\n",
offset);
close(fd);
return offset;
fail:
if (fd >= 0)
close(fd);
return -1;
}
int release_hsa(const char *zcore_hsa_path)
{
int ret;
util_log_print(UTIL_LOG_INFO, "Release HSA memory via %s\n",
zcore_hsa_path);
/* Release HSA memory */
ret = util_file_write_s("0", zcore_hsa_path);
if (ret < 0) {
util_log_print(UTIL_LOG_ERROR, "File write failed (%s)\n",
strerror(errno));
return -1;
}
/* Verify that HSA memory has been released */
if (get_hsa_size(zcore_hsa_path) > 0) {
util_log_print(UTIL_LOG_ERROR, "HSA memory release failed\n");
return -1;
}
util_log_print(UTIL_LOG_INFO, "HSA memory successfully released\n");
return 0;
}