kdump/kdump-0.8.9-detect-xen-dumps.patch

310 lines
9.0 KiB
Diff

From: Petr Tesarik <ptesarik@suse.cz>
Subject: Add '-X' to makedumpfile when dumping a Xen host
References: bnc#864910
Patch-mainline: 0.8.10
When dumping a Xen virtualization host, kdump should dump only Dom0 and
hypervisor pages, i.e. it should exclude all DomU pages.
A kdumptool flag is introduced to override this default behaviour.
Signed-off-by: Petr Tesarik <ptesarik@suse.cz>
---
NEWS | 4 +
doc/man/kdump.5.txt.in | 7 +-
kdumptool/savedump.cc | 9 ++
kdumptool/util.cc | 166 +++++++++++++++++++++++++++++++++++++++++++++++++
kdumptool/util.h | 20 +++++
sysconfig.kdump.in | 3
6 files changed, 206 insertions(+), 3 deletions(-)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+0.8.10
+------
+ * Filter out DomU pages, when dumping a Xen virtualization host
+
0.8.9
-----
* Fixed dracut hook install
--- a/doc/man/kdump.5.txt.in
+++ b/doc/man/kdump.5.txt.in
@@ -481,7 +481,7 @@ KDUMPTOOL_FLAGS
~~~~~~~~~~~~~~~
This is a space-separated list of flags to tweak the run-time behaviour of
-*kdumptool*(8). Currently, only one flag is supported:
+*kdumptool*(8). These flags are recognized:
*NOSPARSE*::
Disable the creation of sparse-files. This flag is for debugging purposes,
@@ -495,6 +495,11 @@ This is a space-separated list of flags
You can specify this flag to force the use of only one dumping process,
regardless of the value of KDUMP_CPUS.
+*XENALLDOMAINS*::
+ When dumping a Xen virtualization host, *makedumpfile*(8) is normally
+ invoked with the _-X_ option to exclude DomU pages. This flag can be
+ used to include all pages in the dump.
+
Default: ""
KDUMP_NETCONFIG
--- a/kdumptool/savedump.cc
+++ b/kdumptool/savedump.cc
@@ -275,7 +275,12 @@ void SaveDump::saveDump(const RootDirURL
cerr << "Splitting ELF dumps is not supported." << endl;
}
- if (useElf && dumplevel == 0) {
+ bool excludeDomU = false;
+ if (!config->kdumptoolContainsFlag("XENALLDOMAINS") &&
+ Util::isXenCoreDump(m_dump.c_str()))
+ excludeDomU = true;
+
+ if (useElf && dumplevel == 0 && !excludeDomU) {
// use file source?
provider = new FileDataProvider(m_dump.c_str());
m_useMakedumpfile = false;
@@ -287,6 +292,8 @@ void SaveDump::saveDump(const RootDirURL
cmdline << "--split ";
cmdline << config->MAKEDUMPFILE_OPTIONS.value() << " ";
cmdline << "-d " << config->KDUMP_DUMPLEVEL.value() << " ";
+ if (excludeDomU)
+ cmdline << "-X ";
if (useElf)
cmdline << "-E ";
if (useCompressed)
--- a/kdumptool/util.cc
+++ b/kdumptool/util.cc
@@ -26,6 +26,7 @@
#include <sys/types.h>
#include <sys/utsname.h>
#include <sys/stat.h>
+#include <sys/mman.h>
#include <libelf.h>
#include <gelf.h>
@@ -162,6 +163,171 @@ bool Util::isElfFile(const string &file)
} catch (...) {
close(fd);
throw;
+ }
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------------
+static off_t FindElfNoteByName(int fd, off_t offset, size_t sz,
+ const char *name)
+ throw (KError)
+{
+ char *buf, *p;
+ size_t to_read;
+ size_t nlen;
+ off_t ret = (off_t)-1;
+
+ Debug::debug()->trace("FindElfNoteByName(%d, %lu, %lu, %s)",
+ fd, (unsigned long)offset, (unsigned long)sz, name);
+
+ if (lseek(fd, offset, SEEK_SET) == (off_t)-1)
+ throw KSystemError("Cannot seek to ELF notes", errno);
+
+ buf = new char[sz];
+ try {
+ to_read = sz;
+ p = buf;
+ while (to_read) {
+ ssize_t bytes_read = read(fd, p, to_read);
+ if (bytes_read < 0)
+ throw KSystemError("Cannot read ELF note", errno);
+ else if (!bytes_read)
+ throw KError("Unexpected EOF while reading ELF note");
+
+ to_read -= bytes_read;
+ p += bytes_read;
+ }
+
+ nlen = strlen(name);
+ to_read = sz;
+ p = buf;
+ while (to_read) {
+ Elf64_Nhdr *hdr = reinterpret_cast<Elf64_Nhdr*>(p);
+ if (to_read < sizeof(*hdr))
+ break;
+ to_read -= sizeof(*hdr);
+ p += sizeof(*hdr);
+
+ size_t notesz =
+ ((hdr->n_namesz + 3) & (-(Elf64_Word)4)) +
+ ((hdr->n_descsz + 3) & (-(Elf64_Word)4));
+ if (to_read < notesz)
+ break;
+
+ if ((hdr->n_namesz == nlen && !memcmp(p, name, nlen)) ||
+ (hdr->n_namesz == nlen+1 && !memcmp(p, name, nlen+1))) {
+ ret = offset + (p - buf) - sizeof(*hdr);
+ break;
+ }
+
+ to_read -= notesz;
+ p += notesz;
+ }
+ } catch (...) {
+ delete buf;
+ throw;
+ }
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------------
+#define ELF_HEADER_MAPSIZE (128*1024)
+
+bool Util::isXenCoreDump(int fd)
+ throw (KError)
+{
+ void *map = MAP_FAILED;
+ Elf *elf = (Elf*)0;
+ bool ret;
+
+ Debug::debug()->trace("isXenCoreDump(%d)", fd);
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ throw KError("libelf is out of date.");
+
+ try {
+ map = mmap(NULL, ELF_HEADER_MAPSIZE, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (map == MAP_FAILED) {
+ map = mmap(NULL, ELF_HEADER_MAPSIZE, PROT_READ,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (map == MAP_FAILED)
+ throw KSystemError("Cannot allocate ELF headers", errno);
+
+ size_t to_read = ELF_HEADER_MAPSIZE;
+ char *p = reinterpret_cast<char *>(map);
+ while (to_read) {
+ ssize_t bytes_read = read(fd, p, to_read);
+ if (bytes_read < 0)
+ throw KSystemError("ELF read error", errno);
+ else if (!bytes_read)
+ break;
+
+ to_read -= bytes_read;
+ p += bytes_read;
+ }
+ }
+ elf = elf_memory(reinterpret_cast<char *>(map), ELF_HEADER_MAPSIZE);
+ if (!elf)
+ throw KELFError("elf_memory() failed", elf_errno());
+
+ if (elf_kind(elf) != ELF_K_ELF)
+ return false;
+
+ switch (gelf_getclass(elf)) {
+ case ELFCLASS32:
+ case ELFCLASS64:
+ break;
+ default:
+ throw KError("Unrecognized ELF class");
+ }
+
+ size_t phnum, i;
+ if (elf_getphdrnum(elf, &phnum))
+ throw KELFError("Cannot count ELF program headers", elf_errno());
+
+ for (i = 0; i < phnum; ++i) {
+ GElf_Phdr phdr;
+
+ if (gelf_getphdr(elf, i, &phdr) != &phdr)
+ throw KELFError("getphdr() failed.", elf_errno());
+
+ if (phdr.p_type == PT_NOTE &&
+ FindElfNoteByName(fd, phdr.p_offset, phdr.p_filesz, "Xen")
+ != (off_t)-1) {
+ ret = true;
+ break;
+ }
+ }
+ } catch (...) {
+ if (elf)
+ elf_end(elf);
+ if (map != MAP_FAILED)
+ munmap(map, ELF_HEADER_MAPSIZE);
+ throw;
+ }
+
+ munmap(map, ELF_HEADER_MAPSIZE);
+ elf_end(elf);
+ return ret;
+}
+
+// -----------------------------------------------------------------------------
+bool Util::isXenCoreDump(const string &file)
+ throw (KError)
+{
+ int fd = open(file.c_str(), O_RDONLY);
+ if (fd < 0) {
+ throw KSystemError("Opening of " + file + " failed.", errno);
+ }
+
+ bool ret;
+ try {
+ ret = isXenCoreDump(fd);
+ } catch (...) {
+ close(fd);
+ throw;
}
return ret;
--- a/kdumptool/util.h
+++ b/kdumptool/util.h
@@ -94,6 +94,26 @@ class Util {
throw (KError);
/**
+ * Checks if @p filename is a Xen core dump.
+ *
+ * @param[in] filename the file to check
+ * @return @c true if it's a Xen core dump, @c false otherwise
+ * @exception KError if opening the file failed
+ */
+ static bool isXenCoreDump(const std::string &filename)
+ throw (KError);
+
+ /**
+ * Checks if @p filename is a Xen core dump.
+ *
+ * @param[in] fd a file descriptor
+ * @return @c true if it's a Xen core dump, @c false otherwise
+ * @exception KError if opening the file failed
+ */
+ static bool isXenCoreDump(int fd)
+ throw (KError);
+
+ /**
* Frees a vector.
*/
template <typename T>
--- a/sysconfig.kdump.in
+++ b/sysconfig.kdump.in
@@ -260,7 +260,7 @@ KDUMP_POSTSCRIPT=""
#
KDUMP_COPY_KERNEL="yes"
-## Type: string(NOSPARSE,NOSPLIT)
+## Type: string(NOSPARSE,NOSPLIT,XENALLDOMAINS)
## Default: ""
## ServiceRestart: kdump
#
@@ -268,6 +268,7 @@ KDUMP_COPY_KERNEL="yes"
#
# NOSPARSE disable creation of sparse files.
# NOSPLIT do not pass "--split" to makedumpfile even if KDUMP_CPUS > 1
+# XENALLDOMAINS do not filter out Xen DomU pages
#
# See also: kdump(5).
#