[PATCH] coredump: add filesz truncation and filter

Jacob Lalonde <[email protected]>
Newsgroups org.kvack.linux-mm,org.kernel.vger.linux-fsdevel,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
From: Jacob Lalonde <[email protected]>

This adds opt-in truncation of Coredump segments to
`/proc/pid/coredump_filter`. The primary motivation here is to reduce the
number of zero pages written via pipe to a user space coredump process. In
my testing this reduces coredump size, and thus IO by ~40% at Meta. With
some outliers such as PyTorch's TBE weights being loaded in right before a
crash being closer to 99%.

We achieve this by having the Kernel not emit the trailing zeros of any
VMA, resulting in a PT_LOAD with filesz < memsz. I verified that both GDB
from v16 onward and trunk LLDB support loading cores with truncated
sections, however LLDB won't report zeros for the truncated region

I elected to iterate page by page for simplicity, and because we
short-circuit when encountering the first faulted in page, meaning time
spent iterating should directly replace slower copying and pipe IPC.

Below is an example program where the entire 1 GB VMA would be emitted,
where as with the patch only the first page would be written.

int main(void) {
     void *p = mmap(NULL, MMAP_SIZE, PROT_READ | PROT_WRITE,
                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);

    int* p2 = (int*)p;
    /* write a sentinel to make sure it's not fully sparse */
    p2[0] = 0xDEADBEEF;

    abort();
}

Signed-off-by: Jacob Lalonde <[email protected]>
---
 fs/coredump.c            | 44 +++++++++++++++++++++++++++++++++++++---
 include/linux/mm_types.h |  3 ++-
 2 files changed, 43 insertions(+), 4 deletions(-)

diff --git a/fs/coredump.c b/fs/coredump.c
index e68a76ff92a3..b6cee412eb99 100644
--- a/fs/coredump.c
+++ b/fs/coredump.c
@@ -1588,6 +1588,42 @@ static bool always_dump_vma(struct vm_area_struct *vma)
 
 #define DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER 1
 
+/*
+ * Truncate the file_sz of the VMA to the last faulted page
+ */
+static unsigned long truncate_vma(struct vm_area_struct *vma)
+{
+	/*
+	 * Same logic as dump_user_range, where we enumerate the pages
+	 * in a VMA, but instead of skipping un-faulted pages, we move the VMA
+	 * end
+	 */
+	struct page *page;
+	unsigned long truncated_end;
+
+	/* We're already under the mmap lock */
+	int locked = 1;
+
+	for (truncated_end = vma->vm_end; truncated_end > vma->vm_start; truncated_end -= PAGE_SIZE) {
+		/*
+		 * Because we're iterating backwards, we need to
+		 * look at the page before the current address
+		 */
+		unsigned long probe_addr = truncated_end - PAGE_SIZE;
+
+		page = get_dump_page(probe_addr, &locked);
+		/*
+		 * We hit a faulted page, exit
+		 */
+		if (page) {
+			put_page(page);
+			break;
+		}
+	}
+
+	return truncated_end - vma->vm_start;
+}
+
 /*
  * Decide how much of @vma's contents should be included in a core dump.
  */
@@ -1662,13 +1698,15 @@ static unsigned long vma_dump_size(struct vm_area_struct *vma,
 		return DUMP_SIZE_MAYBE_ELFHDR_PLACEHOLDER;
 	}
 
-#undef	FILTER
-
 	return 0;
 
 whole:
-	return vma->vm_end - vma->vm_start;
+	if (FILTER(TRUNCATE_SPARSE_VMAS))
+		return truncate_vma(vma);
+	else
+		return vma->vm_end - vma->vm_start;
 }
+#undef	FILTER
 
 /*
  * Helper function for iterating across a vma list.  It ensures that the caller
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index b18c2b2e7d2c..18cf8304f698 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -1932,9 +1932,10 @@ enum {
 #define MMF_DUMP_HUGETLB_SHARED  8
 #define MMF_DUMP_DAX_PRIVATE	9
 #define MMF_DUMP_DAX_SHARED	10
+#define MMF_DUMP_TRUNCATE_SPARSE_VMAS 11
 
 #define MMF_DUMP_FILTER_SHIFT	MMF_DUMPABLE_BITS
-#define MMF_DUMP_FILTER_BITS	9
+#define MMF_DUMP_FILTER_BITS	10
 #define MMF_DUMP_FILTER_MASK \
 	((BIT(MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
 #define MMF_DUMP_FILTER_DEFAULT \
-- 
2.53.0-Meta
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.