From: R Nageswara Sastry <rnsastry@linux.ibm.com>
To: Christian Brauner <brauner@kernel.org>, linux-fsdevel@vger.kernel.org
Cc: Jacob Lalonde <jalalonde@meta.com>,
Josef Bacik <josef@toxicpanda.com>, Jann Horn <jannh@google.com>,
Alexander Viro <viro@zeniv.linux.org.uk>, Jan Kara <jack@suse.cz>,
Andrew Morton <akpm@linux-foundation.org>,
David Hildenbrand <david@kernel.org>,
Lorenzo Stoakes <ljs@kernel.org>,
"Liam R. Howlett" <liam@infradead.org>,
Vlastimil Babka <vbabka@kernel.org>,
Mike Rapoport <rppt@kernel.org>,
Suren Baghdasaryan <surenb@google.com>,
Michal Hocko <mhocko@suse.com>,
Omar Sandoval <osandov@osandov.com>,
Jacob Lalonde <jalalonde@fb.com>, Shuah Khan <shuah@kernel.org>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
linux-kselftest@vger.kernel.org, linuxppc-dev@lists.ozlabs.org
Subject: Re: [PATCH v2 22/22] selftests/coredump: show how to inspect the task to decide how the coredump should be sent
Date: Wed, 9 Sep 2026 21:37:07 +0530 [thread overview]
Message-ID: <8a6c3ee9-2904-4459-a7ce-0dd3a862c45c@linux.ibm.com> (raw)
In-Reply-To: <20260820-work-coredump-sparse-v2-22-ba32dd718c51@kernel.org>
On 20.08.2026 4:39 AM, Christian Brauner wrote:
> The kernel blocks in the coredump req until the coredump ack is sent by
> the coredump server. This allows the coredump server to decide how the
> kernel is supposed to send the coredump.
>
> Let's show how that can work:
>
> - a task that has a large memory mapping gets sent as a sparse record
> stream
>
> - a task with a trivial memory mapping gets sent as a plain byte stream
>
> Since the threads are parked in coredump_task_exit() with their mm
> around we can look at /proc/<pid>/statm to figure out what the task has
> mapped.
>
> Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Tested-by: R Nageswara Sastry <rnsastry@linux.ibm.com>
System: ppc64le LPAR (IBM POWER), Linux 7.3-rc2
> ---
> .../coredump/coredump_socket_protocol_test.c | 184 +++++++++++++++++++++
> .../selftests/coredump/coredump_test_helpers.c | 58 +++++++
> .../selftests/coredump/coredump_test_helpers.h | 7 +-
> 3 files changed, 248 insertions(+), 1 deletion(-)
>
> diff --git a/tools/testing/selftests/coredump/coredump_socket_protocol_test.c b/tools/testing/selftests/coredump/coredump_socket_protocol_test.c
> index f33eaf2fa93d..daff908232a2 100644
> --- a/tools/testing/selftests/coredump/coredump_socket_protocol_test.c
> +++ b/tools/testing/selftests/coredump/coredump_socket_protocol_test.c
> @@ -2136,4 +2136,188 @@ TEST_F(coredump, socket_request_sparse_without_records)
> check_conflicting_ack(_metadata, self, COREDUMP_KERNEL | COREDUMP_SPARSE);
> }
>
> +/* What the server reports back about the coredump it decided to take. */
> +struct stream_choice {
> + bool sparse;
> + ssize_t received;
> + off_t size;
> + ssize_t vm_size;
> +};
> +
> +/*
> + * The kernel blocks in the coredump request until the ack arrives, so a
> + * coredump server gets to look at the task before it commits to a
> + * stream. Take the record stream only for a task whose mappings are
> + * worth it and the plain byte stream for everything else.
> + */
> +static void check_stream_choice(struct __test_metadata *const _metadata,
> + FIXTURE_DATA(coredump) *self, bool big,
> + struct stream_choice *choice)
> +{
> + int pidfd, status;
> + pid_t pid, pid_coredump_server;
> + struct pidfd_info info = {};
> + int ipc_sockets[2];
> + int pipefds[2];
> + char c;
> +
> + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets), 0);
> + ASSERT_EQ(pipe(pipefds), 0);
> + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket"));
> +
> + pid_coredump_server = fork();
> + ASSERT_GE(pid_coredump_server, 0);
> + if (pid_coredump_server == 0) {
> + int fd_server = -1, fd_coredump = -1, fd_peer_pidfd = -1;
> + int fd_file = -1;
> + int exit_code = EXIT_FAILURE;
> + struct coredump_req req = {};
> + struct stream_choice got = {};
> + __u64 mask;
> +
> + close(ipc_sockets[0]);
> + close(pipefds[0]);
> +
> + fd_server = create_and_listen_unix_socket("/tmp/coredump.socket");
> + if (fd_server < 0)
> + goto out;
> +
> + if (write_nointr(ipc_sockets[1], "1", 1) < 0)
> + goto out;
> +
> + close(ipc_sockets[1]);
> +
> + fd_coredump = accept4(fd_server, NULL, NULL, SOCK_CLOEXEC);
> + if (fd_coredump < 0)
> + goto out;
> +
> + fd_peer_pidfd = get_peer_pidfd(fd_coredump);
> + if (fd_peer_pidfd < 0)
> + goto out;
> +
> + /*
> + * The reassembled coredump is bigger than the mapping the
> + * child made, so keep it on the detached tmpfs and sparse.
> + */
> + fd_file = open_coredump_tmpfile(self->fd_tmpfs_detached);
> + if (fd_file < 0)
> + goto out;
> +
> + if (!read_coredump_req(fd_coredump, &req))
> + goto out;
> +
> + if (!check_coredump_req(&req))
> + goto out;
> +
> + /*
> + * Nothing is on the wire yet and the kernel is waiting for
> + * the ack, so there is all the time in the world to look at
> + * the task and decide what to ask it for.
> + */
> + got.vm_size = peer_vm_size(fd_peer_pidfd);
> + if (got.vm_size < 0)
> + goto out;
> + got.sparse = got.vm_size >= SPARSE_STREAM_THRESHOLD;
> +
> + fprintf(stderr, "Peer maps %zd bytes, asking for %s\n",
> + got.vm_size,
> + got.sparse ? "a sparse record stream" : "a byte stream");
> +
> + mask = COREDUMP_KERNEL | COREDUMP_WAIT;
> + if (got.sparse)
> + mask |= COREDUMP_RECORDS | COREDUMP_SPARSE;
> +
> + if (!send_coredump_ack(fd_coredump, &req, mask, 0))
> + goto out;
> +
> + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK))
> + goto out;
> +
> + if (got.sparse) {
> + got.received = recv_coredump_records(fd_coredump, fd_file,
> + &got.size, NULL, -1);
> + } else {
> + got.received = recv_coredump_bytes(fd_coredump, fd_file);
> + got.size = got.received;
> + }
> + if (got.received < 0)
> + goto out;
> +
> + /* Either way a debugger has to see an ordinary core file. */
> + if (!is_elf_core(fd_file))
> + goto out;
> +
> + if (write_nointr(pipefds[1], &got, sizeof(got)) != sizeof(got))
> + goto out;
> +
> + exit_code = EXIT_SUCCESS;
> +out:
> + close(pipefds[1]);
> + if (fd_file >= 0)
> + close(fd_file);
> + if (fd_peer_pidfd >= 0)
> + close(fd_peer_pidfd);
> + if (fd_coredump >= 0)
> + close(fd_coredump);
> + if (fd_server >= 0)
> + close(fd_server);
> + _exit(exit_code);
> + }
> + self->pid_coredump_server = pid_coredump_server;
> +
> + EXPECT_EQ(close(ipc_sockets[1]), 0);
> + EXPECT_EQ(close(pipefds[1]), 0);
> + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1);
> + EXPECT_EQ(close(ipc_sockets[0]), 0);
> +
> + pid = fork();
> + ASSERT_GE(pid, 0);
> + if (pid == 0)
> + crashing_child_sparse(big ? SPARSE_MAPPING_SIZE : PAGE_SIZE);
> +
> + pidfd = sys_pidfd_open(pid, 0);
> + ASSERT_GE(pidfd, 0);
> +
> + waitpid(pid, &status, 0);
> + ASSERT_TRUE(WIFSIGNALED(status));
> + ASSERT_TRUE(WCOREDUMP(status));
> +
> + ASSERT_EQ(read_nointr(pipefds[0], choice, sizeof(*choice)),
> + sizeof(*choice));
> + EXPECT_EQ(close(pipefds[0]), 0);
> +
> + ASSERT_TRUE(get_pidfd_info(pidfd, &info));
> + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0);
> + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0);
> +
> + wait_and_check_coredump_server(pid_coredump_server, _metadata, self);
> +}
> +
> +/* A task with little mapped isn't worth a record stream. */
> +TEST_F(coredump, socket_request_stream_choice_small)
> +{
> + struct stream_choice choice = {};
> +
> + check_stream_choice(_metadata, self, false, &choice);
> +
> + ASSERT_LT(choice.vm_size, (ssize_t)SPARSE_STREAM_THRESHOLD);
> + ASSERT_FALSE(choice.sparse);
> + ASSERT_GT(choice.received, 0);
> +}
> +
> +/* A task sitting on a big mapping is. */
> +TEST_F(coredump, socket_request_stream_choice_large)
> +{
> + struct stream_choice choice = {};
> +
> + check_stream_choice(_metadata, self, true, &choice);
> +
> + ASSERT_GE(choice.vm_size, (ssize_t)SPARSE_STREAM_THRESHOLD);
> + ASSERT_TRUE(choice.sparse);
> + ASSERT_GT(choice.size, (off_t)SPARSE_MAPPING_SIZE);
> +
> + /* The holes didn't have to go over the socket. */
> + ASSERT_LT(choice.received, choice.size / 8);
> +}
> +
> TEST_HARNESS_MAIN
> diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/tools/testing/selftests/coredump/coredump_test_helpers.c
> index 9346b8f688e2..d7cc448eeaf4 100644
> --- a/tools/testing/selftests/coredump/coredump_test_helpers.c
> +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c
> @@ -1095,6 +1095,33 @@ int check_compact_coredump(int fd_object, int fd_reference)
> return ret;
> }
>
> +/* Read a plain coredump byte stream to end-of-file. */
> +ssize_t recv_coredump_bytes(int fd_coredump, int fd_core_file)
> +{
> + ssize_t received = 0;
> +
> + for (;;) {
> + char buffer[PAGE_SIZE];
> + ssize_t ret = read_nointr(fd_coredump, buffer, sizeof(buffer));
> +
> + if (ret < 0) {
> + fprintf(stderr, "%s: read failed: %m\n", __func__);
> + return -1;
> + }
> + if (ret == 0)
> + break;
> +
> + if (write_nointr(fd_core_file, buffer, ret) != ret) {
> + fprintf(stderr, "%s: write failed: %m\n", __func__);
> + return -1;
> + }
> + received += ret;
> + }
> +
> + fprintf(stderr, "Received %zd bytes of coredump\n", received);
> + return received;
> +}
> +
> int create_detached_tmpfs(void)
> {
> int fd_context, fd_tmpfs;
> @@ -1190,6 +1217,37 @@ bool get_pidfd_info(int fd_peer_pidfd, struct pidfd_info *info)
> return true;
> }
>
> +/*
> + * How much the peer has mapped. The task is parked in the coredump
> + * handshake, so its mm is still there to be looked at.
> + */
> +ssize_t peer_vm_size(int fd_peer_pidfd)
> +{
> + struct pidfd_info info = {};
> + unsigned long pages;
> + char path[64];
> + FILE *f;
> +
> + if (!get_pidfd_info(fd_peer_pidfd, &info))
> + return -1;
> +
> + snprintf(path, sizeof(path), "/proc/%d/statm", info.pid);
> + f = fopen(path, "r");
> + if (!f) {
> + fprintf(stderr, "%s: %s: %m\n", __func__, path);
> + return -1;
> + }
> +
> + if (fscanf(f, "%lu", &pages) != 1) {
> + fprintf(stderr, "%s: %s: no size\n", __func__, path);
> + fclose(f);
> + return -1;
> + }
> + fclose(f);
> +
> + return (ssize_t)pages * sysconf(_SC_PAGESIZE);
> +}
> +
> /* Protocol helper functions */
>
> ssize_t recv_marker(int fd)
> diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.h b/tools/testing/selftests/coredump/coredump_test_helpers.h
> index 00d695b67b3f..97ad5cfeae92 100644
> --- a/tools/testing/selftests/coredump/coredump_test_helpers.h
> +++ b/tools/testing/selftests/coredump/coredump_test_helpers.h
> @@ -18,6 +18,9 @@
> /* Size of the mostly unpopulated mapping the sparse coredump test maps. */
> #define SPARSE_MAPPING_SIZE (256 * 1024 * 1024)
>
> +/* A task mapping at least this much is worth a record stream. */
> +#define SPARSE_STREAM_THRESHOLD (SPARSE_MAPPING_SIZE / 2)
> +
> /* Shared helper function declarations */
> void *do_nothing(void *arg);
> void crashing_child(void);
> @@ -25,9 +28,11 @@ void crashing_child_sparse(size_t size);
> ssize_t recv_coredump_records(int fd_coredump, int fd_core_file,
> off_t *coredump_size, bool *truncated,
> int fd_peer_pidfd);
> -bool is_elf_core(int fd);
> ssize_t recv_coredump_compact(int fd_coredump, int fd_object, int fd_reference,
> off_t *coredump_size);
> +ssize_t recv_coredump_bytes(int fd_coredump, int fd_core_file);
> +ssize_t peer_vm_size(int fd_peer_pidfd);
> +bool is_elf_core(int fd);
> int check_compact_coredump(int fd_object, int fd_reference);
> int create_detached_tmpfs(void);
> int create_and_listen_unix_socket(const char *path);
>
--
Thanks and Regards
R.Nageswara Sastry
prev parent reply other threads:[~2026-09-09 16:07 UTC|newest]
Thread overview: 47+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-19 23:09 [PATCH v2 00/22] coredump: allow to create sparse coredumps on the coredump socket Christian Brauner
2026-08-19 23:09 ` [PATCH v2 01/22] powerpc/spufs: don't dump more than the note supports Christian Brauner
2026-09-09 15:52 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 02/22] coredump: refuse negative skips Christian Brauner
2026-09-09 15:53 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 03/22] coredump: set the minimum send buffer size Christian Brauner
2026-09-09 15:53 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 04/22] selftests/coredump: discard the right amount after the coredump request Christian Brauner
2026-09-09 15:54 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 05/22] selftests/coredump: collapse the expected request check into the helper Christian Brauner
2026-09-09 15:54 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 06/22] selftests/coredump: add a separate helper header Christian Brauner
2026-09-09 15:55 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 07/22] coredump: pin the protocol struct sizes Christian Brauner
2026-09-09 15:55 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 08/22] coredump: move the negotiated mask into struct coredump_params Christian Brauner
2026-09-09 15:56 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 09/22] coredump: deduplicate the to_skip flush Christian Brauner
2026-09-09 15:56 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 10/22] coredump: make the dump helper return bool Christian Brauner
2026-09-09 15:59 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 11/22] coredump: always chunk writes Christian Brauner
2026-09-09 16:00 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 12/22] coredump: clean up coredump state handling Christian Brauner
2026-09-09 16:01 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 13/22] coredump: add COREDUMP_RECORDS to the coredump socket protocol Christian Brauner
2026-09-09 16:02 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 14/22] coredump: add COREDUMP_SPARSE " Christian Brauner
2026-09-09 16:02 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 15/22] tools: sync coredump.h header Christian Brauner
2026-09-09 16:03 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 16/22] coredump: send the coredump in records if requested Christian Brauner
2026-09-09 16:04 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 17/22] coredump: describe the holes when COREDUMP_SPARSE is negotiated Christian Brauner
2026-09-09 16:04 ` R Nageswara Sastry
2026-09-09 16:21 ` David Hildenbrand (Arm)
2026-08-19 23:09 ` [PATCH v2 18/22] selftests/coredump: test COREDUMP_RECORDS and COREDUMP_SPARSE Christian Brauner
2026-09-09 16:05 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 19/22] selftests/coredump: hand the record stream to a sink Christian Brauner
2026-09-09 16:05 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 20/22] selftests/coredump: put a hole in the middle of a sparse mapping Christian Brauner
2026-09-09 16:06 ` R Nageswara Sastry
2026-09-09 16:18 ` David Hildenbrand (Arm)
2026-08-19 23:09 ` [PATCH v2 21/22] selftests/coredump: simulate a blob store Christian Brauner
2026-09-09 16:06 ` R Nageswara Sastry
2026-08-19 23:09 ` [PATCH v2 22/22] selftests/coredump: show how to inspect the task to decide how the coredump should be sent Christian Brauner
2026-09-09 16:07 ` R Nageswara Sastry [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8a6c3ee9-2904-4459-a7ce-0dd3a862c45c@linux.ibm.com \
--to=rnsastry@linux.ibm.com \
--cc=akpm@linux-foundation.org \
--cc=brauner@kernel.org \
--cc=david@kernel.org \
--cc=jack@suse.cz \
--cc=jalalonde@fb.com \
--cc=jalalonde@meta.com \
--cc=jannh@google.com \
--cc=josef@toxicpanda.com \
--cc=liam@infradead.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-kselftest@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linuxppc-dev@lists.ozlabs.org \
--cc=ljs@kernel.org \
--cc=mhocko@suse.com \
--cc=osandov@osandov.com \
--cc=rppt@kernel.org \
--cc=shuah@kernel.org \
--cc=surenb@google.com \
--cc=vbabka@kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox