From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7DF6A21CC71; Tue, 11 Aug 2026 15:27:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462059; cv=none; b=HpdOyTuvoUodyqTkpa5yrZ7Xd9/ezl6JGUu24a7jc8vPWAsNPWvfnEATd+BfmgmB+sBsV0TfmlZbc7VHxD6o95uv3BuQZyUR06sl+C+qdauoUyDpLzS0+ew0SAcp2vJxKEQhzxHZgq7/tfDRdkDEU51zK17StwjAZ3YdWr5zS/c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462059; c=relaxed/simple; bh=9qfTBP7vyCivJLvwjV8igaT+fa50Nmgpl18ZhB0KXys=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=sZusbNEbphgTcD4P1r/eV54URJ4L60Q7qHVaGsSaEbia5mje2O259LcfJTrzk6XCtQQE+WV1U4bpH2gADsG7NP0tVTx98jvfEZndiHpxbiNKNJYaTT+ulPYxHOt7PVDdUBlZMosi97lMx46yqNmp2MXPsZpJkfZfzJPgl+PiHyQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mC4py+uv; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mC4py+uv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 065F41F000E9; Tue, 11 Aug 2026 15:27:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462058; bh=CTiS8U5K7y3D0Dlv9kThq0rqgw/f8AQWtxw0lGe/Dc4=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=mC4py+uvPpGye50ncXW6tN5UwwBurfR2YI6g2akn5SfoyucoN96Iuhu+NxGTOrH3o MkqTLLRiH2AM9KlPjaR2x0/fyxoEibIafXOO4O/yk+7kseDcfoaIkc5ywjS76KIh58 uTZGsjBx58J2PC81zMZyAa3QR4lsnnkWNkaeafOqjDnExeGsfDgFeg0O0m2o91+zjy TB1TdF8O5kIbuCnLqub754cG/W44hcDiRBfFXlySYmvNGiETfFDzTm3//KQOSCridE jgNVU4iczl3HxAAwk/QzeZhQD+wpVjBU0+izdycJrar7GDIr9osZh/vZGtrcxKAzJR Hkb2FHgVGGr3A== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:22 +0200 Subject: [PATCH 01/11] selftests/coredump: discard the right amount after the coredump request Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-1-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=2068; i=brauner@kernel.org; h=from:subject:message-id; bh=9qfTBP7vyCivJLvwjV8igaT+fa50Nmgpl18ZhB0KXys=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2ydMf7Yj5mq10YbIOXkbJ95a9/zScZZbVZry5XOvO yzzO73VuqOUhUGMi0FWTJHFod0kXG45T8Vmo0wNmDmsTCBDGLg4BWAiArMYGW7aJ8lq/vFdKsUS 29T9edfMloBLLCp5ugHMK56ferXk0nFGhubEiY8Kd3sz7VsW2vO1z4dNb8lS6azWlYGrFy32vBp iygsA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 read_coredump_req() gets the leftover wrong twice. It takes the absolute difference of the two sizes, so a test binary that knows a larger struct coredump_req than the kernel sends tries to discard bytes that were never sent. And it hands recv() sizeof(buffer) instead of the number of bytes it wants. So MSG_WAITALL waits for a whole page. Either one blocks until the kernel closes the socket. Which it won't because it is waiting for the coredump ack... Its benign today because struct coredump_req hasn't grown. But let's fix it for the future. Compute the leftover as what the kernel sent beyond what was consumed. Fixes: 59cd658eaf40 ("selftests/coredump: add coredump server selftests") Signed-off-by: Christian Brauner (Amutable) --- tools/testing/selftests/coredump/coredump_test_helpers.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/too= ls/testing/selftests/coredump/coredump_test_helpers.c index 2a20faf9cb0a..524fa5370593 100644 --- a/tools/testing/selftests/coredump/coredump_test_helpers.c +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c @@ -235,10 +235,10 @@ bool read_coredump_req(int fd, struct coredump_req *r= eq) fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n", req->size, (unsigned long long)req->mask); =20 - if (user_size > kernel_size) - remaining_size =3D user_size - kernel_size; - else + if (kernel_size > user_size) remaining_size =3D kernel_size - user_size; + else + remaining_size =3D 0; =20 if (PAGE_SIZE <=3D remaining_size) return false; @@ -250,7 +250,7 @@ bool read_coredump_req(int fd, struct coredump_req *req) if (remaining_size) { char buffer[PAGE_SIZE]; =20 - ret =3D recv(fd, buffer, sizeof(buffer), MSG_WAITALL); + ret =3D recv(fd, buffer, remaining_size, MSG_WAITALL); if (ret !=3D remaining_size) return false; fprintf(stderr, "Discarded %zu bytes of data after coredump request\n", = remaining_size); --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6098A3AE187; Tue, 11 Aug 2026 15:27:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462064; cv=none; b=Bk53+hRAmZNIGYawxzIXs57W1RlrDHHZCnLpN/k9BBCI65M3NlxVEdoWjfniAu5OioiHfaEdabMZccsEYcygWN639nOqmkE7qyMGdUHBz7jXOTsYcpaNwUq4dtfrMsVbCulNF2WranmZm8Lb2Q9/j7YIkUaaK6+vTmqatbuptpY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462064; c=relaxed/simple; bh=/WE7FwKgQXlwVzHyeztNVUhNPPEXhv6nrZrHM54peHw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=qENp+77oDa3sNcTZiLdTUZxDa3M46elcOymj8jwlrEDTVkwtbMm8lqfXXxKFRtllbn39g+E8GAREXtxceTAkpcwPAhSCgu32JduHL0a4h22ZgMrdvus7iFPUSCk3FUXdShbmc7ZH/ZG+FrMIJCpn9TQY6UNStC6x8TvNmR8vTI0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=a/6/bnLe; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="a/6/bnLe" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B4FCF1F00A3A; Tue, 11 Aug 2026 15:27:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462063; bh=vem2xsFlpo0+sWC3l/kxNB7POgGE6gpeRa35NgLYw6I=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=a/6/bnLeoX9AstuTEYVT9BGZD2qYKRDb97wunLXwXts7QaNjyUzcB5AHy5sjmE40S 6opyHuFyx3LhMRWACbJ/XkJtuqANTlhEjlPNcZEkSi8vDJkvRDME+UPn7SdBi78rjc DD52380Eoh9d2MJJaC+QBRqfQYJn3+96s0nVG/H2LObZXr+1vTOiDGvlq3UmEvbI0G BmDptAGWxSW6a/7tnZ10RCk+iblQlTDJSkY1oJnWgkijjuMuE1/0y/1Rcay6oNxL5J KwP08f4hpXhgWT1dknZL72SB1kMKA7ex6IcgtCc9q4MhWD+eaKAN8BzxL162v46ymx icMeoJuuFGO8g== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:23 +0200 Subject: [PATCH 02/11] selftests/coredump: collapse the expected request check into the helper Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-2-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=8194; i=brauner@kernel.org; h=from:subject:message-id; bh=/WE7FwKgQXlwVzHyeztNVUhNPPEXhv6nrZrHM54peHw=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2ydwMay6tdplnk7BlGnv9XXXbezfymfu0n9sQf7/T 5bLM8Med5SyMIhxMciKKbI4tJuEyy3nqdhslKkBM4eVCWQIAxenAExk6UyGvxJ8D2052yc/nq9e bnvk9TyetNBdKy40vrB7fpxDQmVzriMjQ9+Dk0d2d3q2LvTZylSuo+C89iHLr+4F+dlCT23N64O MGQE= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 All nine callers spell the expected flags. So every new feature bit the kernel learns has to be cargo culted. The callers also all pass COREDUMP_ACK_SIZE_VER0 as the minimum request size although what is being validated is coredump_req->size. And read_coredump_req() makes the same mixup twice more. Clean this all up. Signed-off-by: Christian Brauner (Amutable) --- .../coredump/coredump_socket_protocol_test.c | 36 ++++++------------= ---- tools/testing/selftests/coredump/coredump_test.h | 3 +- .../selftests/coredump/coredump_test_helpers.c | 35 +++++++++++++-----= --- 3 files changed, 32 insertions(+), 42 deletions(-) diff --git a/tools/testing/selftests/coredump/coredump_socket_protocol_test= .c b/tools/testing/selftests/coredump/coredump_socket_protocol_test.c index d9fa6239b5a9..60a357e628eb 100644 --- a/tools/testing/selftests/coredump/coredump_socket_protocol_test.c +++ b/tools/testing/selftests/coredump/coredump_socket_protocol_test.c @@ -151,9 +151,7 @@ TEST_F(coredump, socket_request_kernel) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_kernel: check_coredump_req failed\n"); goto out; } @@ -301,9 +299,7 @@ TEST_F(coredump, socket_request_userspace) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_userspace: check_coredump_req failed\n"= ); goto out; } @@ -441,9 +437,7 @@ TEST_F(coredump, socket_request_reject) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_reject: check_coredump_req failed\n"); goto out; } @@ -581,9 +575,7 @@ TEST_F(coredump, socket_request_invalid_flag_combinatio= n) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_invalid_flag_combination: check_coredum= p_req failed\n"); goto out; } @@ -702,9 +694,7 @@ TEST_F(coredump, socket_request_unknown_flag) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_unknown_flag: check_coredump_req failed= \n"); goto out; } @@ -822,9 +812,7 @@ TEST_F(coredump, socket_request_invalid_size_small) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_invalid_size_small: check_coredump_req = failed\n"); goto out; } @@ -944,9 +932,7 @@ TEST_F(coredump, socket_request_invalid_size_large) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_request_invalid_size_large: check_coredump_req = failed\n"); goto out; } @@ -1355,9 +1341,7 @@ TEST_F_TIMEOUT(coredump, socket_multiple_crashing_cor= edumps, 500) goto out; } =20 - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "check_coredump_req failed for fd %d\n", fd_coredump); goto out; } @@ -1509,9 +1493,7 @@ TEST_F_TIMEOUT(coredump, socket_multiple_crashing_cor= edumps_epoll_workers, 500) fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: rea= d_coredump_req failed\n"); goto out; } - if (!check_coredump_req(&req, COREDUMP_ACK_SIZE_VER0, - COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT)) { + if (!check_coredump_req(&req)) { fprintf(stderr, "socket_multiple_crashing_coredumps_epoll_workers: che= ck_coredump_req failed\n"); goto out; } diff --git a/tools/testing/selftests/coredump/coredump_test.h b/tools/testi= ng/selftests/coredump/coredump_test.h index ed47f01fa53c..a02809145e2d 100644 --- a/tools/testing/selftests/coredump/coredump_test.h +++ b/tools/testing/selftests/coredump/coredump_test.h @@ -51,8 +51,7 @@ bool read_marker(int fd, enum coredump_mark mark); bool read_coredump_req(int fd, struct coredump_req *req); bool send_coredump_ack(int fd, const struct coredump_req *req, __u64 mask, size_t size_ack); -bool check_coredump_req(const struct coredump_req *req, size_t min_size, - __u64 required_mask); +bool check_coredump_req(const struct coredump_req *req); int open_coredump_tmpfile(int fd_tmpfs_detached); void process_coredump_worker(int fd_coredump, int fd_peer_pidfd, int fd_co= re_file); =20 diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/too= ls/testing/selftests/coredump/coredump_test_helpers.c index 524fa5370593..d32d96436779 100644 --- a/tools/testing/selftests/coredump/coredump_test_helpers.c +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c @@ -200,7 +200,7 @@ bool read_marker(int fd, enum coredump_mark mark) bool read_coredump_req(int fd, struct coredump_req *req) { ssize_t ret; - size_t field_size, user_size, ack_size, kernel_size, remaining_size; + size_t field_size, user_size, known, kernel_size, remaining_size; =20 memset(req, 0, sizeof(*req)); field_size =3D sizeof(req->size); @@ -214,9 +214,9 @@ bool read_coredump_req(int fd, struct coredump_req *req) } kernel_size =3D req->size; =20 - if (kernel_size < COREDUMP_ACK_SIZE_VER0) { + if (kernel_size < COREDUMP_REQ_SIZE_VER0) { fprintf(stderr, "read_coredump_req: kernel_size %zu < min %d\n", - kernel_size, COREDUMP_ACK_SIZE_VER0); + kernel_size, COREDUMP_REQ_SIZE_VER0); return false; } if (kernel_size >=3D PAGE_SIZE) { @@ -225,11 +225,11 @@ bool read_coredump_req(int fd, struct coredump_req *r= eq) return false; } =20 - /* Use the minimum of user and kernel size to read the full request. */ + /* Consume as much of the request as we know about. */ user_size =3D sizeof(struct coredump_req); - ack_size =3D user_size < kernel_size ? user_size : kernel_size; - ret =3D recv(fd, req, ack_size, MSG_WAITALL); - if (ret !=3D ack_size) + known =3D user_size < kernel_size ? user_size : kernel_size; + ret =3D recv(fd, req, known, MSG_WAITALL); + if (ret !=3D known) return false; =20 fprintf(stderr, "Read coredump request with size %u and mask 0x%llx\n", @@ -287,15 +287,24 @@ bool send_coredump_ack(int fd, const struct coredump_= req *req, return true; } =20 -bool check_coredump_req(const struct coredump_req *req, size_t min_size, - __u64 required_mask) +/* Every option the kernel is expected to advertise in coredump_req->mask.= */ +#define COREDUMP_REQ_MASK_ALL \ + (COREDUMP_KERNEL | COREDUMP_USERSPACE | \ + COREDUMP_REJECT | COREDUMP_WAIT) + +bool check_coredump_req(const struct coredump_req *req) { - if (req->size < min_size) - return false; - if ((req->mask & required_mask) !=3D required_mask) + if (req->size < COREDUMP_REQ_SIZE_VER0) { + fprintf(stderr, "%s: size %u below minimum %d\n", + __func__, req->size, COREDUMP_REQ_SIZE_VER0); return false; - if (req->mask & ~required_mask) + } + if (req->mask !=3D COREDUMP_REQ_MASK_ALL) { + fprintf(stderr, "%s: mask 0x%llx, expected 0x%llx\n", + __func__, (unsigned long long)req->mask, + (unsigned long long)COREDUMP_REQ_MASK_ALL); return false; + } return true; } =20 --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 12BD93B27D1; Tue, 11 Aug 2026 15:27:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462069; cv=none; b=Z38yJ7TuomAnTCjeR5Y79Cjo4CHl/b5klldBsHo3MIhl5u9+xtBRHSxXlTG38VilOmu1GIlxh8cq8DF0CoJUN1tbZOt76DRPeNrZQIdi/3T0fe8ippp5Sc0vIdlYg3OcuUD0g1YlvybYepwFd0kmrZ6L/YXXGkvW4uUjuHyobo4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462069; c=relaxed/simple; bh=SpbEtOACwAfhrvnTo3HVdvq33xeffDHxwIh3irpBTA8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=YZnp5x90/aJWUXf8kaWuCCp+I1d/38E9A0ur2G9UnD6EZ4dl0WU9011y5tOAxNE5GJwKN9A1BahVJSWj1eqz8wkC81otOIATR23+os9qN0UDm7JXH0WJQXdhSjgCbGa1bf8vtCI6tXaUA1ijH4S405214FRECFJxsB19t/nAxrg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=e7buYwgU; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="e7buYwgU" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 711681F00A3D; Tue, 11 Aug 2026 15:27:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462067; bh=X0X4qAQGOj4Ws5+MdwykOepn652tQT1tcVQqlter/BI=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=e7buYwgUaziBc1ANvD2UI/ojDa/PK9hy0xEryGVTXt6hhAv7BxZr0pk6eXRo0lUW5 H9sZllbu01qd/GbMN5wZ33oz87qkFzZ1py+pMuA0BLhmM/YI/Y3RHrBrj96nzs//4r tddLT9TnZLRlv7mEEKH9BI1kOiCWw9TOljnV7zOi20v+29vzVrK62DpFJzoNmYpVIB 9o8B79PymbbumxLEcysFVZWMb3grWg5R8xsmCG/IhpRQeQ7sglY3a4/vq/CY1wkdL+ HHB/NrYicMzwPdAmIEUZTTby0tNrYO7SRCl204XN/Jtfk+cVR9EtxNaZpeh4aFUzsC Eb3CalwVNeCoA== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:24 +0200 Subject: [PATCH 03/11] coredump: pin the protocol struct sizes Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-3-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=1989; i=brauner@kernel.org; h=from:subject:message-id; bh=SpbEtOACwAfhrvnTo3HVdvq33xeffDHxwIh3irpBTA8=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yfsmr3WqlU8LPaH6vTjssqJdXo/M2eXLTouF8eXW Rt102ZbRykLgxgXg6yYIotDu0m43HKeis1GmRowc1iZQIYwcHEKwES+JDP8MxP6V1N1ZL7jwuMa ltxbn3vKHWFcHCyzaEKda7fdOkn1x4wMbS+mtx8/v+HX7U4+hR3Vr7wZIlMn8D7/Gxb10aR7V+1 GJgA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 COREDUMP_REQ_SIZE_VER0 and COREDUMP_ACK_SIZE_VER0 define the initial struct sizes. Assert that both published sizes still match their structs, next to the assert the coredump marks already have. While at it fix the "currently know" typo in the doc. Signed-off-by: Christian Brauner (Amutable) --- fs/coredump.c | 2 ++ include/uapi/linux/coredump.h | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index e68a76ff92a3..235b54484107 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -752,6 +752,8 @@ static inline bool coredump_sock_send(struct file *file= , struct coredump_req *re return ret =3D=3D sizeof(*req); } =20 +static_assert(sizeof(struct coredump_req) =3D=3D COREDUMP_REQ_SIZE_VER0); +static_assert(sizeof(struct coredump_ack) =3D=3D COREDUMP_ACK_SIZE_VER0); static_assert(sizeof(enum coredump_mark) =3D=3D sizeof(__u32)); =20 static inline bool coredump_sock_mark(struct file *file, enum coredump_mar= k mark) diff --git a/include/uapi/linux/coredump.h b/include/uapi/linux/coredump.h index dc3789b78af0..662e0468da6e 100644 --- a/include/uapi/linux/coredump.h +++ b/include/uapi/linux/coredump.h @@ -30,11 +30,11 @@ enum { * member is set to the size of struct coredump_req and provides a hint * to userspace how much data can be read. Userspace may use MSG_PEEK to * peek the size of struct coredump_req and then choose to consume it in - * one go. Userspace may also simply read a COREDUMP_ACK_SIZE_VER0 + * one go. Userspace may also simply read a COREDUMP_REQ_SIZE_VER0 * request. If the size the kernel sends is larger userspace simply * discards any remaining data. * - * The coredump_req->mask member is set to the currently know features. + * The coredump_req->mask member is set to the currently known features. * Userspace may only set coredump_ack->mask to the bits raised by the * kernel in coredump_req->mask. * --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DE3763B27D1; Tue, 11 Aug 2026 15:27:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462074; cv=none; b=dSWXKY9SHPmoKjWEz1XFu4E8cLww25gEyo8+ITzj6+ossE9RjGjpTHkvyRo33EBXy9yu/YAdc5N05kRhO/UtJQ4wI0Ju+S2tHyVswv9Swx0FqYWXcnyY0Hxnmetl/hUVg7vZCreCYis3EZBT6dH8aFXiEKVDE7ZgmyHC4vyEX7s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462074; c=relaxed/simple; bh=K4UcjnUezF0qgQQhwKLrhjcWPbcfz3yDCnnpkkFGKnU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=H7Hj0gyLkwytXtXUAxYXbE2+Ku+HunFn1qZMviVtX+I2DO5krs0dUAWPPDKIn5Tx7NYaAmXMohsn8G1zmXPC+naM/HG+gsNH4mrXzh0oFZa8/cD5rm4bbqJC+u44JQGMbVaOVkt3CSZQoiVvC9BXxfO1KpR5Osh+TbXdLnVGOOA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=FHzFovP2; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="FHzFovP2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 310B01F000E9; Tue, 11 Aug 2026 15:27:48 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462072; bh=scXxx601mt6vWMI18eOyOCejMZkwRvYbtnRftKjb/YQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=FHzFovP2ddptgqb3hUEvdYZm6detD/ssggmG4/VehxrJFPlKYr3AoHpl+Cl061n/Q XwHNbmac91L5kjKEbP44HyUcCzpoFZVEQOIFI3jE1qdDLunr+2K2rpPKO7nOQWJd/O lCtxmyXeNzFLG5fKWBCQSBt6Ym7PbgQACBiQ/OCxgwLrSiwgtH8vQp1423vDzWY1Ca /Fi8ttEuz/NMACiIjb1Ev/Ssa48QEZdVsKfjMZI9/rvwFE731aPQuWt5tlQm2wsNyo W8E8lmiDjPnUZGb+h/iWbPwEv3lffjvcpoI/bbcOmS5WjuthK9+RlPBnBRonENDli7 bXol+3srViP+g== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:25 +0200 Subject: [PATCH 04/11] coredump: move the negotiated mask into struct coredump_params Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-4-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=3058; i=brauner@kernel.org; h=from:subject:message-id; bh=K4UcjnUezF0qgQQhwKLrhjcWPbcfz3yDCnnpkkFGKnU=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2ycEOEd3hNmfvLDqgNbj7Ue75e40zstJfHnv35OdK 4wyj3z72lHKwiDGxSArpsji0G4SLrecp2KzUaYGzBxWJpAhDFycAjCR4mhGhstCNx/da2gS2O0z o7nKW/+dkFpcRI9pk/RJ/2V8bgye0xkZtn56VvldIHAfe1rbjNR4A76EJanPpX4mWJW7PHvy5U4 ZPwA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 The coredump server negotiates a set of COREDUMP_* options with the kernel. The core dump path cannot see them though. Move the mask into struct coredump_params so the negotiated options are available to the core dump path. No functional change. Signed-off-by: Christian Brauner (Amutable) --- fs/coredump.c | 15 +++++++-------- include/linux/coredump.h | 2 ++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 235b54484107..e5463e3b3f4b 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -100,7 +100,6 @@ struct core_name { unsigned int core_pipe_limit; bool core_dumped; enum coredump_type_t core_type; - u64 mask; }; =20 static int expand_corename(struct core_name *cn, int size) @@ -245,9 +244,9 @@ static bool coredump_parse(struct core_name *cn, struct= coredump_params *cprm, int pid_in_pattern =3D 0; int err =3D 0; =20 - cn->mask =3D COREDUMP_KERNEL; + cprm->mask =3D COREDUMP_KERNEL; if (core_pipe_limit) - cn->mask |=3D COREDUMP_WAIT; + cprm->mask |=3D COREDUMP_WAIT; cn->used =3D 0; cn->corename =3D NULL; cn->core_pipe_limit =3D 0; @@ -853,7 +852,7 @@ static bool coredump_sock_request(struct core_name *cn,= struct coredump_params * return false; } =20 - cn->mask =3D ack.mask; + cprm->mask =3D ack.mask; return coredump_sock_mark(cprm->file, COREDUMP_MARK_REQACK); } =20 @@ -1122,7 +1121,7 @@ static void do_coredump(struct core_name *cn, struct = coredump_params *cprm, } =20 /* Don't even generate the coredump. */ - if (cn->mask & COREDUMP_REJECT) + if (cprm->mask & COREDUMP_REJECT) return; =20 /* get us an unshared descriptor table; almost always a no-op */ @@ -1130,13 +1129,13 @@ static void do_coredump(struct core_name *cn, struc= t coredump_params *cprm, if (unshare_files()) return; =20 - if ((cn->mask & COREDUMP_KERNEL) && !coredump_write(cn, cprm, binfmt)) + if ((cprm->mask & COREDUMP_KERNEL) && !coredump_write(cn, cprm, binfmt)) return; =20 coredump_sock_shutdown(cprm->file); =20 /* Let the parent know that a coredump was generated. */ - if (cn->mask & COREDUMP_USERSPACE) + if (cprm->mask & COREDUMP_USERSPACE) cn->core_dumped =3D true; =20 /* @@ -1144,7 +1143,7 @@ static void do_coredump(struct core_name *cn, struct = coredump_params *cprm, * or usermodehelper to finish before exiting so it can e.g., * inspect /proc/. */ - if (cn->mask & COREDUMP_WAIT) { + if (cprm->mask & COREDUMP_WAIT) { switch (cn->core_type) { case COREDUMP_PIPE: wait_for_dump_helpers(cprm->file); diff --git a/include/linux/coredump.h b/include/linux/coredump.h index 7b38ee2e7913..dc7a05b1bb0a 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -26,6 +26,8 @@ struct coredump_params { /* Snapshot of dumpable at dump start. */ enum task_dumpable dumpable; int cpu; + /* COREDUMP_* options negotiated with the coredump server. */ + u64 mask; loff_t written; loff_t pos; loff_t to_skip; --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 924CA3B5302; Tue, 11 Aug 2026 15:27:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462078; cv=none; b=OcwMuEck/vSDIHpxh01VuNTXpDUOGW4CCbkDa8I0v8OBPzej8T60mqnLA7mVf+/3+AWXCOCHT3njg78KihAcIH/1RISrgI3FuFbPLviPqdisDOhhQlyfbkHui8PGHR2MEPD7WwNiHmDvJy34zxFDSn0hZ+Sm7XGhppuLqUSEIyc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462078; c=relaxed/simple; bh=eVMaTke3Zp4rPM/gpT2jPr6BY6R4nqbkomTRcFn86hM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=dNqALU5DTo7ZJawbBf7DFTuF2oTenPsfshK3nLz/MBDjsuRzf4JFEHygQwYFwoRT39L1XHIihdGwCM4W0OjsSmWJjo4wmgQtr7OQvJcllEVJlOHnTK6JuFxmhj52x4WxpJZRuJlcjmG1Qc1g/Kr40halI8w/Ki3woj59L1kr4RU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=jePYbKst; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="jePYbKst" Received: by smtp.kernel.org (Postfix) with ESMTPSA id F01F91F00A3D; Tue, 11 Aug 2026 15:27:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462077; bh=wC90oFJa7Ier1ZIhf5weT54crOnc3p7uwLYcRogSj00=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=jePYbKstnrnoDIjieNdlMvUl5SIrd0wrHkgAuTO3eaOIgdr7AFT4TKPO1sJIRxYin TdSEGeMgruFr2uzZMrInAsZf9k89iH3drJCAnciUoAlKTFyGGyjkAzdy2dwvkfEylg 34xPZP/lsSRvTh3SgDH0B9nNEkYVkGN/3/iKEwC8WvX+4pFlLO7uZvaMwDaM8CYFZH AtUdwbBKc4Y/5PRUTymt9mEOZpL8nl40HMdflIIq9AufEZ9p4YW0q09j0ETb+aMMca aPYNbi3Y+rslqxcoKgcukBCTvhREbcu+IMUvI0wi0yI8JLhRjo2Ipexv6cRSgB/HkD 89Kz7qrNZtclw== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:26 +0200 Subject: [PATCH 05/11] coredump: deduplicate the to_skip flush Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-5-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=1458; i=brauner@kernel.org; h=from:subject:message-id; bh=eVMaTke3Zp4rPM/gpT2jPr6BY6R4nqbkomTRcFn86hM=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yecezmdOV++aOm/PzzVsc3bOO+z3+3x2j/NxrDwm 52aZODMjlIWBjEuBlkxRRaHdpNwueU8FZuNMjVg5rAygQxh4OIUgIlk5jEybFbY9nK5xe7db/95 HLnn+nh+v9jxeXf8VBRd7oTk/hJ2ZGRkOPP64DMLb48I+4n3d7LprE+21v4swH47QGiPXfgLIYY GHgA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 dump_emit() and dump_emit_page() open-code the same flush of the accumulated cprm->to_skip. Move it into a helper. No functional change. Signed-off-by: Christian Brauner (Amutable) --- fs/coredump.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index e5463e3b3f4b..6de18bc49925 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -1249,13 +1249,21 @@ static int __dump_skip(struct coredump_params *cprm= , size_t nr) return __dump_emit(cprm, zeroes, nr); } =20 -int dump_emit(struct coredump_params *cprm, const void *addr, int nr) +/* Flush the accumulated hole before writing data. */ +static int dump_flush(struct coredump_params *cprm) { if (cprm->to_skip) { if (!__dump_skip(cprm, cprm->to_skip)) return 0; cprm->to_skip =3D 0; } + return 1; +} + +int dump_emit(struct coredump_params *cprm, const void *addr, int nr) +{ + if (!dump_flush(cprm)) + return 0; return __dump_emit(cprm, addr, nr); } EXPORT_SYMBOL(dump_emit); @@ -1284,11 +1292,8 @@ static int dump_emit_page(struct coredump_params *cp= rm, struct page *page) if (!page) return 0; =20 - if (cprm->to_skip) { - if (!__dump_skip(cprm, cprm->to_skip)) - return 0; - cprm->to_skip =3D 0; - } + if (!dump_flush(cprm)) + return 0; if (cprm->written + PAGE_SIZE > cprm->limit) return 0; if (dump_interrupted()) --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1E60F3A5E87; Tue, 11 Aug 2026 15:28:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462083; cv=none; b=cYmgzsmw+jLXTsx7j8EnVAvEQGmEz1RrG1Opzrh6xxec+wkDpxdUk4b5I4XoQS8PkbZjv2QxUaYFzeec8HCkAGouClFpXp95FOEmQYgr1wnXn0Vtup5ef4U6ogdzCXt9b5H71ijDftEV8hHCsvkQzzhM/Wc3Bj9w2jgVvAObNME= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462083; c=relaxed/simple; bh=4FXENe5nZxm7CHrTOSbNbye686t9axb9imZneIuX9U8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=gCsE8gMh7g6fg8Go2rYKfKBk+kDAjsGtfWVH1y58HX40px/M7jSrDfT5w+zhV82ZNi2TctHn7RoNCM+ljiwXfDaByjaqrdAViBRlR70P9zsiIlDs2ae6tB+tZverXec9KhlGU4o46MgN7ohTlMCZnItDrc5GBtMysE2LgFWoIqU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=K/KBwQ1I; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="K/KBwQ1I" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 987271F00A3E; Tue, 11 Aug 2026 15:27:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462081; bh=/2uicMp+SuinB5ktmPhmPvncPAci8v0nQIiqA6W9Fok=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=K/KBwQ1IHDI1MDYbS7fTsikWbe5KElyxN/AOhZjB5jkNBJTG70ZUanaSe8f+D+AeE N6IKOnLUHHMI54GonNTKAyrWgAlqa6UI0MNe3OwL7GXH+7UrZi8FL8C/JxTP98qeZ3 P/hjhDhdyLH0DO/j9njjDI47FbiDrexz407HbGf0WfRTgR2jHrAzZNFjWLo9vmPQP2 4AHPVTdesd58QdKSTnuWIzPnAQhxI5FS4OPrgZMg8ohXAhHrioU7+nWPf1+XM6FReW y83+xskJ48xIhl4L4mU6138/NG4e/goXvR9nvqU3of/Pchf/EuFjK9THikQsZU50B4 OAIXpFzja6ZcQ== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:27 +0200 Subject: [PATCH 06/11] coredump: add COREDUMP_HEADER to the coredump socket protocol Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-6-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=3783; i=brauner@kernel.org; h=from:subject:message-id; bh=4FXENe5nZxm7CHrTOSbNbye686t9axb9imZneIuX9U8=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yf0HnkQcXbK/a87tu556aPKp3xmncz5ap7feTlT/ 2x6/qrTqqOUhUGMi0FWTJHFod0kXG45T8Vmo0wNmDmsTCBDGLg4BWAi9YUM/yNC4s4dnV+zc/qq Tqb1J9e7VuvNM9zOq+t/7+JdEellDzcy/JUVU40XFa5cXPSh9oT/9bi7AVusjpifVM+5/H6OkzF /NSsA X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 A coredump sent over a socket is a plain byte stream. The kernel knows things about the bytes it is sending that a server might care about. For example, it knows where the unpopulated parts of a mapping are. We can't communicate this to userspace currently though. Add a COREDUMP_HEADER feature bit and a struct coredump_frame_header. Userspace can negotiate that feature. Instead of a byte stream it gets a header plus data. Reassembling the frames yields the same coredump that would have been sent without them. The next patch will introduce a first feature. The frame itself is also versioned and thus extensible with the same protocol as the ack-req sync. A kernel that doesn't know the bit doesn't raise it in coredump_req->mask and a server may not raise a bit the kernel didn't advertise. A server that doesn't know the bit never raises it and gets a plain byte stream. This just adds the infrastructure. Signed-off-by: Christian Brauner (Amutable) --- include/uapi/linux/coredump.h | 52 +++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 52 insertions(+) diff --git a/include/uapi/linux/coredump.h b/include/uapi/linux/coredump.h index 662e0468da6e..5252480d3eec 100644 --- a/include/uapi/linux/coredump.h +++ b/include/uapi/linux/coredump.h @@ -11,12 +11,16 @@ * @COREDUMP_USERSPACE: userspace writes coredump * @COREDUMP_REJECT: don't generate coredump * @COREDUMP_WAIT: wait for coredump server + * @COREDUMP_HEADER: send the coredump as a sequence of frames instead of + * as a plain byte stream, see struct coredump_frame_hea= der; + * requires COREDUMP_KERNEL */ enum { COREDUMP_KERNEL =3D (1ULL << 0), COREDUMP_USERSPACE =3D (1ULL << 1), COREDUMP_REJECT =3D (1ULL << 2), COREDUMP_WAIT =3D (1ULL << 3), + COREDUMP_HEADER =3D (1ULL << 4), }; =20 /** @@ -101,4 +105,52 @@ enum coredump_mark { __COREDUMP_MARK_MAX =3D (1U << 31), }; =20 +/** + * enum coredump_frame_type - Type of a coredump frame + * + * @COREDUMP_FRAME_DATA: the header is followed by ->len bytes of data + * @__COREDUMP_FRAME_MAX: the maximum coredump frame type value + */ +enum coredump_frame_type { + COREDUMP_FRAME_DATA =3D 0U, + __COREDUMP_FRAME_MAX =3D (1U << 31), +}; + +/** + * struct coredump_frame_header - header of a coredump frame + * @size: size of struct coredump_frame_header + * @type: one of enum coredump_frame_type + * @flags: modifiers for this frame + * @offset: offset of this frame in the coredump + * @len: length of this frame in the coredump + * + * If the coredump server raises COREDUMP_HEADER in coredump_ack->mask the + * kernel doesn't send the coredump as a plain byte stream. It sends a + * sequence of frames instead. A struct coredump_frame_header is followed = by + * @len bytes of actual coredump data. + * + * The @size member is set to the size of struct coredump_frame_header the + * kernel knows and lets the header grow later. It comes first so it can be + * peeked. Userspace must consume @size bytes and discard anything beyond + * what it knows. The same way it deals with struct coredump_req. It must + * refuse a @size smaller than COREDUMP_FRAME_HEADER_SIZE_VER0. + * + * The @flags member carries modifiers that change how the frame is to be + * interpreted. No flags are defined yet. Userspace must refuse a frame + * carrying a flag it doesn't know. + * + * COREDUMP_HEADER must be combined with COREDUMP_KERNEL. + */ +struct coredump_frame_header { + __u32 size; + __u32 type; + __u64 flags; + __u64 offset; + __u64 len; +}; + +enum { + COREDUMP_FRAME_HEADER_SIZE_VER0 =3D 32U, /* size of first published struc= t */ +}; + #endif /* _UAPI_LINUX_COREDUMP_H */ --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 48DDA3B71A8; Tue, 11 Aug 2026 15:28:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462089; cv=none; b=DnAlQEhgzOtO3I9yzuVbt9UoUtK13ofPwjPQckE3ZBvnntPhg28/zjPfhxelsJj5r0YuorhtX2oKWjtFlPO00L7uOR9KPfYUF6+zF3arHAxPVZQPzSwxOe0XtYqz9gfzz27fryXqSyuhnel7cJ3FodH2cVrPSOPobl7WMYVI6kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462089; c=relaxed/simple; bh=uBST1XLQTUf+x0hFBtk8wUBZ/6YyWD5sMLzaZ6j7wCs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=By9dTgXqMDkihiXrxsWuMygZlsczmJij00TJxvZO2iwzhjm2b1HYPDZmGI+BTIALIgwfvfFLbGQoMvDcdaHQcSGbSmPQ4q5zJvDCA7+wkzFVCfng/+raoV8eg3I8+Xt+DEcCE7vNav9YeGP+vH6xW2QhSeR+TzOt7ODt4HYOktQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eNbl9TI+; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eNbl9TI+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 400961F000E9; Tue, 11 Aug 2026 15:28:01 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462086; bh=sCoOreTJ2X/U61okovu+QNFm+oz9E14qwVyjp1SenYU=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=eNbl9TI+d6Es9bc/AmTgJ67rm9UG7VS/zO+HHdhXLVol8SmFRI47CW0i13SWMZym/ vePrh2c62xPxDOxkwoTu4jAO9P+Zgd+FeZgsvfV537P7hC4XaKsV/AN/EGkfHmc3tC sF3jx+JRyhJroiIU18oQaqIkABgUW8X3opwfY1YnylUO0lFoHUfvB/YChdsG7w3Bow 4dOlvRGU2Lk7+MVqdjht4kTqujXmvRhIUILx76jTqmyZmB8F7mR6hZO3oXgT0kgESI wD4qtuIgd6al2df5xUQGPK7RpYtcCc9Z0oddjUuKMYPArBgws7dLcGGsQeOh8FMkh1 by7tNafbgiprw== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:28 +0200 Subject: [PATCH 07/11] coredump: add COREDUMP_SPARSE to the coredump socket protocol Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-7-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=3305; i=brauner@kernel.org; h=from:subject:message-id; bh=uBST1XLQTUf+x0hFBtk8wUBZ/6YyWD5sMLzaZ6j7wCs=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yfsV7+0jE90UseLxdeWPnmcv/RASONqk85bkzbMe Mrd1N6/raOUhUGMi0FWTJHFod0kXG45T8Vmo0wNmDmsTCBDGLg4BWAix+UZGZpz2R8uEL4yI//y rQ+5MlV69T2bTR5ksS7sFFVrMdjW2M/w31dBU37BJv7/Z34LL774sKnBTFuTe+tH2fj414HfJOy D+QE= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 A coredump with a lot of unpopulated mappings sends endless amounts of zero data to userspace. This is nonsensical. While __dump_skip() can seek over them when the target is a regular file a socket cannot do this. COREDUMP_HEADER framed the zeroes but it didn't get rid of them. Add a COREDUMP_SPARSE feature bit and a COREDUMP_FRAME_ZERO frame type. A zero frame is a bare header that tells userspace how many zero bytes where skipped. So a hole crosses the socket as one header no matter how long it is. The coredump server can recreate this sparsely. Zero frames only exist inside a framed stream. So COREDUMP_SPARSE requires COREDUMP_HEADER. Signed-off-by: Christian Brauner (Amutable) --- include/uapi/linux/coredump.h | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/include/uapi/linux/coredump.h b/include/uapi/linux/coredump.h index 5252480d3eec..312bafabb467 100644 --- a/include/uapi/linux/coredump.h +++ b/include/uapi/linux/coredump.h @@ -14,6 +14,8 @@ * @COREDUMP_HEADER: send the coredump as a sequence of frames instead of * as a plain byte stream, see struct coredump_frame_hea= der; * requires COREDUMP_KERNEL + * @COREDUMP_SPARSE: describe the holes in the coredump as zero frames + * instead of transferring them; requires COREDUMP_HEADER */ enum { COREDUMP_KERNEL =3D (1ULL << 0), @@ -21,6 +23,7 @@ enum { COREDUMP_REJECT =3D (1ULL << 2), COREDUMP_WAIT =3D (1ULL << 3), COREDUMP_HEADER =3D (1ULL << 4), + COREDUMP_SPARSE =3D (1ULL << 5), }; =20 /** @@ -109,10 +112,13 @@ enum coredump_mark { * enum coredump_frame_type - Type of a coredump frame * * @COREDUMP_FRAME_DATA: the header is followed by ->len bytes of data + * @COREDUMP_FRAME_ZERO: the header stands for ->len zero bytes and is not + * followed by any data * @__COREDUMP_FRAME_MAX: the maximum coredump frame type value */ enum coredump_frame_type { COREDUMP_FRAME_DATA =3D 0U, + COREDUMP_FRAME_ZERO =3D 1U, __COREDUMP_FRAME_MAX =3D (1U << 31), }; =20 @@ -126,8 +132,10 @@ enum coredump_frame_type { * * If the coredump server raises COREDUMP_HEADER in coredump_ack->mask the * kernel doesn't send the coredump as a plain byte stream. It sends a - * sequence of frames instead. A struct coredump_frame_header is followed = by - * @len bytes of actual coredump data. + * sequence of frames instead. A COREDUMP_FRAME_DATA frame is followed by + * @len bytes of actual coredump data. A COREDUMP_FRAME_ZERO frame is + * followed by nothing and stands for @len zero bytes. A server that didn't + * raise COREDUMP_SPARSE never sees a zero frame. * * The @size member is set to the size of struct coredump_frame_header the * kernel knows and lets the header grow later. It comes first so it can be @@ -139,7 +147,8 @@ enum coredump_frame_type { * interpreted. No flags are defined yet. Userspace must refuse a frame * carrying a flag it doesn't know. * - * COREDUMP_HEADER must be combined with COREDUMP_KERNEL. + * COREDUMP_HEADER must be combined with COREDUMP_KERNEL, and + * COREDUMP_SPARSE with COREDUMP_HEADER. */ struct coredump_frame_header { __u32 size; --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 66BDF3B42D3; Tue, 11 Aug 2026 15:28:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462093; cv=none; b=h/ux6qi5h0FzqESraciOk/yVMXpJ33IKQ5ulXBkKaxQxfuRLwAYwV3U1Rfz7UJVuRZusi6jpDVVFi4UAYpLr3DRH0laSC5Pa3n9n3i1j3HPyLxkGB3/wXtkDYvxCttRLcJgBZ4C7f0l7hKhYaRUkcawoubIDhTKSzgOU2QWzxXU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462093; c=relaxed/simple; bh=J+PQgfbapuFtQu/lpytQUE+OgnnVZmVmxqMxiZbP+d8=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Wm+MKXugBqLtXAjLI6o9LBud7knIeXQfCWyDaWfCdv8WHXe7SDrXyjwxQqK9SbBZtuFHHV5Lv6xbP/sc5jr55A1WkdmVRTyayb3TadWEu5s4YzZ9c+dxlMzX/qvDDL6rMTuA3NLnwapTSm7C02TRkS8nNLZysRhknWrDinYsdsE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JyURzhn3; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JyURzhn3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id DF2261F00A3A; Tue, 11 Aug 2026 15:28:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462091; bh=aiM9rGr2K/f+tuwhqreFuuJ12f+/3ydkN5JIi9mR514=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=JyURzhn3XjAcnWiEScQi8/UqT34v+EtK9PIWO1aL/xbGqrmROWJlxuawQ0zj2TNIn mdSc/wJ8OfTYPzeqYptne3SwXSLchu3RUnzvlPpxTDzkn1muQi4ffyTX7rOiKYjPdK s17oHqviPs0IapHVaa8XZjLwVrSi9i1FoQDiB4AZeUOQ9vf74614K2symcIzZlpP7g FNAZX2gF7zep15hvcFXHH+B9mcGI6kfqkw3pyoAvFHtWRH6cXK0VOhNzyHgvwfle76 z0Duap9AF7aGLxHPkFsLFaGcmL57DPfm16fPErIvs1fgAps8Cm5CteE7lZkR85em5O YkNO1IPzzTU2g== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:29 +0200 Subject: [PATCH 08/11] tools: sync coredump.h header Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-8-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=4229; i=brauner@kernel.org; h=from:subject:message-id; bh=J+PQgfbapuFtQu/lpytQUE+OgnnVZmVmxqMxiZbP+d8=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yesOSn0Wr63ryk1puDd6yP8mddjJDheC4Qf0VYQe z1XPrS8o5SFQYyLQVZMkcWh3SRcbjlPxWajTA2YOaxMIEMYuDgFYCIpkYwM2zq2Spb08z2P36Nc 38D3QKY95OoHz9b5UZqKne8vvJr3jJFhtXfQFe6LqywULm2aulx9YkT3orcy5pd/R6TcOaiZdvo QDwA= X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Sync the headers for the selftests. Signed-off-by: Christian Brauner (Amutable) --- tools/include/uapi/linux/coredump.h | 65 +++++++++++++++++++++++++++++++++= ++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/tools/include/uapi/linux/coredump.h b/tools/include/uapi/linux= /coredump.h index dc3789b78af0..312bafabb467 100644 --- a/tools/include/uapi/linux/coredump.h +++ b/tools/include/uapi/linux/coredump.h @@ -11,12 +11,19 @@ * @COREDUMP_USERSPACE: userspace writes coredump * @COREDUMP_REJECT: don't generate coredump * @COREDUMP_WAIT: wait for coredump server + * @COREDUMP_HEADER: send the coredump as a sequence of frames instead of + * as a plain byte stream, see struct coredump_frame_hea= der; + * requires COREDUMP_KERNEL + * @COREDUMP_SPARSE: describe the holes in the coredump as zero frames + * instead of transferring them; requires COREDUMP_HEADER */ enum { COREDUMP_KERNEL =3D (1ULL << 0), COREDUMP_USERSPACE =3D (1ULL << 1), COREDUMP_REJECT =3D (1ULL << 2), COREDUMP_WAIT =3D (1ULL << 3), + COREDUMP_HEADER =3D (1ULL << 4), + COREDUMP_SPARSE =3D (1ULL << 5), }; =20 /** @@ -30,11 +37,11 @@ enum { * member is set to the size of struct coredump_req and provides a hint * to userspace how much data can be read. Userspace may use MSG_PEEK to * peek the size of struct coredump_req and then choose to consume it in - * one go. Userspace may also simply read a COREDUMP_ACK_SIZE_VER0 + * one go. Userspace may also simply read a COREDUMP_REQ_SIZE_VER0 * request. If the size the kernel sends is larger userspace simply * discards any remaining data. * - * The coredump_req->mask member is set to the currently know features. + * The coredump_req->mask member is set to the currently known features. * Userspace may only set coredump_ack->mask to the bits raised by the * kernel in coredump_req->mask. * @@ -101,4 +108,58 @@ enum coredump_mark { __COREDUMP_MARK_MAX =3D (1U << 31), }; =20 +/** + * enum coredump_frame_type - Type of a coredump frame + * + * @COREDUMP_FRAME_DATA: the header is followed by ->len bytes of data + * @COREDUMP_FRAME_ZERO: the header stands for ->len zero bytes and is not + * followed by any data + * @__COREDUMP_FRAME_MAX: the maximum coredump frame type value + */ +enum coredump_frame_type { + COREDUMP_FRAME_DATA =3D 0U, + COREDUMP_FRAME_ZERO =3D 1U, + __COREDUMP_FRAME_MAX =3D (1U << 31), +}; + +/** + * struct coredump_frame_header - header of a coredump frame + * @size: size of struct coredump_frame_header + * @type: one of enum coredump_frame_type + * @flags: modifiers for this frame + * @offset: offset of this frame in the coredump + * @len: length of this frame in the coredump + * + * If the coredump server raises COREDUMP_HEADER in coredump_ack->mask the + * kernel doesn't send the coredump as a plain byte stream. It sends a + * sequence of frames instead. A COREDUMP_FRAME_DATA frame is followed by + * @len bytes of actual coredump data. A COREDUMP_FRAME_ZERO frame is + * followed by nothing and stands for @len zero bytes. A server that didn't + * raise COREDUMP_SPARSE never sees a zero frame. + * + * The @size member is set to the size of struct coredump_frame_header the + * kernel knows and lets the header grow later. It comes first so it can be + * peeked. Userspace must consume @size bytes and discard anything beyond + * what it knows. The same way it deals with struct coredump_req. It must + * refuse a @size smaller than COREDUMP_FRAME_HEADER_SIZE_VER0. + * + * The @flags member carries modifiers that change how the frame is to be + * interpreted. No flags are defined yet. Userspace must refuse a frame + * carrying a flag it doesn't know. + * + * COREDUMP_HEADER must be combined with COREDUMP_KERNEL, and + * COREDUMP_SPARSE with COREDUMP_HEADER. + */ +struct coredump_frame_header { + __u32 size; + __u32 type; + __u64 flags; + __u64 offset; + __u64 len; +}; + +enum { + COREDUMP_FRAME_HEADER_SIZE_VER0 =3D 32U, /* size of first published struc= t */ +}; + #endif /* _UAPI_LINUX_COREDUMP_H */ --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B87003C3448; Tue, 11 Aug 2026 15:28:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462097; cv=none; b=lXJNfKid1MTtEkon3732NTPRnXaV3zbYh8UfPaPTq3jqHzee/IZP4WUPsumeOYyIxnt6ERlgHHP0Wj+CcBUkokAlNL1dF402M3Sm5nZt00xbAx4spSBMCDkh82kAHmKHcDnauo7GcPi7y+rIYjvTNhuBovissQM+kc/nyJbwKaI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462097; c=relaxed/simple; bh=alEfNKjHn75QOeONKfhCSgPaz/2H5W5/8cuW6aJdyZA=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=hJ6e9ulMMeSh1fY3rPysTW30Up1/qmtIAD7LzFOAEwU3/I2X1zTXAm0HT7QUY5mkZakvJ+hpdu9CQzair+EsgzvTyQ2cMlUl9zIsOgergPuVy3eR5PffXO9MaCR5Vty2ZAzDjD8qGA6YHrpTMOhmTSh6JMgxOV8/wUdJGc7uQZI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=eF/KLJqR; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="eF/KLJqR" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 72DC01F00A3E; Tue, 11 Aug 2026 15:28:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462095; bh=ZOqbnGTbnp8gHK6gI4lu72AVOFkLmNDTl8IC1onEIFc=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=eF/KLJqRJGBst06e6C09PM+yqAMHmRoRME4BL7t2AF7HxY8Y4WMou9G9aog8WAQll ptoyGUxzKNoa2kXWg+luR6QhNOUTiB7vK7ha0h2McMxVjGVxqPLQwy0qMI4uTMJ1Mq fxMUQ0mBDoVNBdccfoGYnHaT5DOFMa+8+dLS8peHVQR3t7mEDG5qc8OVwyPL5yu5nf YUNyngbRaq7/hdLICTLZhDJnuIfdsoHARVo4IWN47u6eAhj4bdKmLVFDKyGGmcQc/X VczGSgwr+TU5uv3rSlVyl5iR8SitbIGyZgXPnzZXOBwy7WelKEFDzLA4Z2uHdqin+t FQ63P2VPDKrTA== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:30 +0200 Subject: [PATCH 09/11] coredump: frame the coredump when COREDUMP_HEADER is negotiated Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-9-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=8790; i=brauner@kernel.org; h=from:subject:message-id; bh=alEfNKjHn75QOeONKfhCSgPaz/2H5W5/8cuW6aJdyZA=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2ycozdPZe3pK4SHVCas4dMtErBN2bOoqXZy2cMlap 4SX3EkpHaUsDGJcDLJiiiwO7Sbhcst5KjYbZWrAzGFlAhnCwMUpABMJOMbwP+aWUXSxe4/lmh4W 1i+PhXL7xVWPC+wqV9nS/FC0w6X9PMP/Irnb0UXWVmKqC3/1fpkpMtOUTddEo+9svfjVjzo5pxn 4AA== X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 When the coredump server raises COREDUMP_HEADER every write to the socket is prefixed with a struct coredump_frame_header in front of it describing what follows. A header and the bytes it describes go out in one iovec. Both emitters write through one helper that either writes the whole iov_iter or fails. So a single place advances the file position. cprm->pos stays the offset in the coredump and keeps ignoring the framing overhead. dump_skip_to() and dump_align() compute from it. cprm->written counts what was handed to the file and so picks the headers up. The two are the same number when the coredump isn't framed. A hole is flushed through __dump_emit() like before. So zeroes still are sent on the socket as actual data frames. Making holes cheap is COREDUMP_SPARSE's job. Signed-off-by: Christian Brauner (Amutable) --- fs/coredump.c | 114 ++++++++++++++++-= ---- include/linux/coredump.h | 5 + .../selftests/coredump/coredump_test_helpers.c | 2 +- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 6de18bc49925..364c89c5f82a 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -51,7 +51,6 @@ #include #include #include -#include =20 #include #include @@ -753,6 +752,7 @@ static inline bool coredump_sock_send(struct file *file= , struct coredump_req *re =20 static_assert(sizeof(struct coredump_req) =3D=3D COREDUMP_REQ_SIZE_VER0); static_assert(sizeof(struct coredump_ack) =3D=3D COREDUMP_ACK_SIZE_VER0); +static_assert(sizeof(struct coredump_frame_header) =3D=3D COREDUMP_FRAME_H= EADER_SIZE_VER0); static_assert(sizeof(enum coredump_mark) =3D=3D sizeof(__u32)); =20 static inline bool coredump_sock_mark(struct file *file, enum coredump_mar= k mark) @@ -798,7 +798,8 @@ static bool coredump_sock_request(struct core_name *cn,= struct coredump_params * struct coredump_req req =3D { .size =3D sizeof(struct coredump_req), .mask =3D COREDUMP_KERNEL | COREDUMP_USERSPACE | - COREDUMP_REJECT | COREDUMP_WAIT, + COREDUMP_REJECT | COREDUMP_WAIT | + COREDUMP_HEADER, .size_ack =3D sizeof(struct coredump_ack), }; struct coredump_ack ack =3D {}; @@ -847,11 +848,24 @@ static bool coredump_sock_request(struct core_name *c= n, struct coredump_params * return false; } =20 + /* Framing only applies to a coredump the kernel writes. */ + if ((ack.mask & COREDUMP_HEADER) && !(ack.mask & COREDUMP_KERNEL)) { + coredump_sock_mark(cprm->file, COREDUMP_MARK_CONFLICTING); + return false; + } + if (ack.spare) { coredump_sock_mark(cprm->file, COREDUMP_MARK_UNSUPPORTED); return false; } =20 + /* Frame header scratch; a bvec can't point at the stack. */ + if (ack.mask & COREDUMP_HEADER) { + cprm->frame =3D kmalloc_obj(*cprm->frame); + if (!cprm->frame) + return false; + } + cprm->mask =3D ack.mask; return coredump_sock_mark(cprm->file, COREDUMP_MARK_REQACK); } @@ -1053,9 +1067,10 @@ static bool coredump_write(struct core_name *cn, cn->core_dumped =3D binfmt->core_dump(cprm); /* * Ensures that file size is big enough to contain the current - * file postion. This prevents gdb from complaining about + * file position. This prevents gdb from complaining about * a truncated file if the last "write" to the file was - * dump_skip. + * dump_skip. A framed coredump relies on it too: the flush + * emits the frames that cover a trailing hole. */ if (cprm->to_skip) { cprm->to_skip--; @@ -1075,6 +1090,7 @@ static void coredump_cleanup(struct core_name *cn, st= ruct coredump_params *cprm) atomic_dec(&core_pipe_count); } kfree(cn->corename); + kfree(cprm->frame); coredump_finish(cn->core_dumped); } =20 @@ -1208,24 +1224,72 @@ void vfs_coredump(const kernel_siginfo_t *siginfo) * do on a core-file: use only these functions to write out all the * necessary info. */ -static int __dump_emit(struct coredump_params *cprm, const void *addr, int= nr) +static bool dump_framed(const struct coredump_params *cprm) +{ + return cprm->mask & COREDUMP_HEADER; +} + +/* Describe the next @len bytes of the coredump. Returns the header size. = */ +static size_t dump_frame_init(struct coredump_params *cprm, + enum coredump_frame_type type, u64 len) +{ + if (!dump_framed(cprm)) + return 0; + + *cprm->frame =3D (struct coredump_frame_header) { + .size =3D sizeof(*cprm->frame), + .type =3D type, + .offset =3D cprm->pos, + .len =3D len, + }; + + return sizeof(*cprm->frame); +} + +/* Write @iter whole or fail. @len is what it advances the coredump by. */ +static bool dump_write_iter(struct coredump_params *cprm, struct iov_iter = *iter, + size_t len) { struct file *file =3D cprm->file; + size_t count =3D iov_iter_count(iter); loff_t pos =3D file->f_pos; ssize_t n; =20 + n =3D __kernel_write_iter(file, iter, &pos); + if (n < 0 || (size_t)n !=3D count) + return false; + file->f_pos =3D pos; + cprm->written +=3D count; + cprm->pos +=3D len; + + return true; +} + +static int __dump_emit(struct coredump_params *cprm, const void *addr, int= nr) +{ + struct kvec kvec[2]; + struct iov_iter iter; + unsigned int nseg =3D 0; + size_t hdr; + if (cprm->written + nr > cprm->limit) return 0; if (dump_interrupted()) return 0; - n =3D __kernel_write(file, addr, nr, &pos); - if (n !=3D nr) - return 0; - file->f_pos =3D pos; - cprm->written +=3D n; - cprm->pos +=3D n; =20 - return 1; + hdr =3D dump_frame_init(cprm, COREDUMP_FRAME_DATA, nr); + if (hdr) { + kvec[nseg].iov_base =3D cprm->frame; + kvec[nseg].iov_len =3D hdr; + nseg++; + } + kvec[nseg].iov_base =3D (void *)addr; + kvec[nseg].iov_len =3D nr; + nseg++; + + iov_iter_kvec(&iter, ITER_SOURCE, kvec, nseg, hdr + nr); + + return dump_write_iter(cprm, &iter, nr); } =20 static int __dump_skip(struct coredump_params *cprm, size_t nr) @@ -1283,11 +1347,10 @@ EXPORT_SYMBOL(dump_skip); #ifdef CONFIG_ELF_CORE static int dump_emit_page(struct coredump_params *cprm, struct page *page) { - struct bio_vec bvec; + struct bio_vec bvec[2]; struct iov_iter iter; - struct file *file =3D cprm->file; - loff_t pos; - ssize_t n; + unsigned int nseg =3D 0; + size_t hdr; =20 if (!page) return 0; @@ -1298,17 +1361,16 @@ static int dump_emit_page(struct coredump_params *c= prm, struct page *page) return 0; if (dump_interrupted()) return 0; - pos =3D file->f_pos; - bvec_set_page(&bvec, page, PAGE_SIZE, 0); - iov_iter_bvec(&iter, ITER_SOURCE, &bvec, 1, PAGE_SIZE); - n =3D __kernel_write_iter(cprm->file, &iter, &pos); - if (n !=3D PAGE_SIZE) - return 0; - file->f_pos =3D pos; - cprm->written +=3D PAGE_SIZE; - cprm->pos +=3D PAGE_SIZE; =20 - return 1; + /* Hand the frame to the same write as the page it describes. */ + hdr =3D dump_frame_init(cprm, COREDUMP_FRAME_DATA, PAGE_SIZE); + if (hdr) + bvec_set_virt(&bvec[nseg++], cprm->frame, hdr); + bvec_set_page(&bvec[nseg++], page, PAGE_SIZE, 0); + + iov_iter_bvec(&iter, ITER_SOURCE, bvec, nseg, hdr + PAGE_SIZE); + + return dump_write_iter(cprm, &iter, PAGE_SIZE); } =20 /* diff --git a/include/linux/coredump.h b/include/linux/coredump.h index dc7a05b1bb0a..06ccd3046a06 100644 --- a/include/linux/coredump.h +++ b/include/linux/coredump.h @@ -6,6 +6,7 @@ #include #include #include +#include #include =20 #ifdef CONFIG_COREDUMP @@ -28,7 +29,11 @@ struct coredump_params { int cpu; /* COREDUMP_* options negotiated with the coredump server. */ u64 mask; + /* Frame header scratch, NULL unless the coredump is framed. */ + struct coredump_frame_header *frame; + /* Bytes handed to the file, frame headers included. */ loff_t written; + /* Offset in the coredump, frame headers excluded. */ loff_t pos; loff_t to_skip; int vma_count; diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/too= ls/testing/selftests/coredump/coredump_test_helpers.c index d32d96436779..bfe10bc51618 100644 --- a/tools/testing/selftests/coredump/coredump_test_helpers.c +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c @@ -290,7 +290,7 @@ bool send_coredump_ack(int fd, const struct coredump_re= q *req, /* Every option the kernel is expected to advertise in coredump_req->mask.= */ #define COREDUMP_REQ_MASK_ALL \ (COREDUMP_KERNEL | COREDUMP_USERSPACE | \ - COREDUMP_REJECT | COREDUMP_WAIT) + COREDUMP_REJECT | COREDUMP_WAIT | COREDUMP_HEADER) =20 bool check_coredump_req(const struct coredump_req *req) { --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6C5E53B8945; Tue, 11 Aug 2026 15:28:20 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462102; cv=none; b=jwBWqxM1HrCm5l7/z/cb6uxgRFIo6jV4ZkgWNq2dgaArsEK7RFK4daN5kQO2JX4hks4gPTPaw17XOUBR6yEXHPYiTxMN8/0FBsnGl0FjtS6SPAbroZNkF1WWn48Eqpr85s65/YGGrRkEALKxVmGKA2gozCqs95BpuenDaaMt1kg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462102; c=relaxed/simple; bh=ZREoaOSeNd4qGwZma6jQbBcL6Gnn8lrPJS0/WXVe/dw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cal/QehVQlWr+v+zlJOkA2p0Oh5e4SktWA4b7jC/5VkUkQ2Ua0rlKRXfbxeUsnb7WhezXKJE4qZ5VsDeMLskavdFXfVmfdwXf3dEs0GaApkA6sdHgQ+HAW6q/25ZnkHrJ6+/i/9iDkLfy4Guf4MR64igTxikoh+g5lOQEC1rR7Y= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Mb9S3/Uu; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Mb9S3/Uu" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 111561F000E9; Tue, 11 Aug 2026 15:28:15 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462100; bh=PxUCP2iDYTzzrW7IUVfims64s4a5dm9b+PmFryUZrZ8=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=Mb9S3/UuLLKJmdNADIKN4evkrOh/0EM77aCNrmNn633IfCAUbYFAxtYpdMaXve6am YxJ+hQYiJVAPpvYEDPlXZN/Pam5Fh62zyP5Pqj2uetgNrxWIFNqdtSZn06pJvluFem ukBxj9q5MRxR1PPdhIJ10WbiCM4eIJUvq3p3Cqm2VMgn078PEr8LRNVqGKEwAXMgGn gtssV3mDKmP80P5EBQtpjqj/zEvfpXVhrVNCuZC/suMFbE0NgJmYrLIEZYOkM8Nsq9 gYKR0wu6cKCTCIPBQxvUQFlXWp6IZPlb6Pv2rUxP9SCm7WD5l31dNFtkqXNbPd1WcT Khn/HCmSQNcNw== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:31 +0200 Subject: [PATCH 10/11] coredump: describe the holes when COREDUMP_SPARSE is negotiated Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-10-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=3730; i=brauner@kernel.org; h=from:subject:message-id; bh=ZREoaOSeNd4qGwZma6jQbBcL6Gnn8lrPJS0/WXVe/dw=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yfULnTvMQy5H/pvOYOhvdqC1Y7mYRd3aoYlG2/M/ HT9QJVSRykLgxgXg6yYIotDu0m43HKeis1GmRowc1iZQIYwcHEKwEQUzjIy9DF+ztB4382XpKfD tyKd353h6EQ/x3kM2gX6EpJaPlMXMjJ8OrvFTP3VHUExebEJF2tsphmdO/cobtXuKI105e6Z55n 4AQ== X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Offer COREDUMP_SPARSE in coredump_req->mask now that there is something behind it. Refuse it without COREDUMP_HEADER. A zero frame cannot exist outside a framed stream. A trailing hole is flushed by coredump_write() the way it always was. So its last byte goes out as a one-byte data frame and the frames cover the whole coredump. Signed-off-by: Christian Brauner (Amutable) --- fs/coredump.c | 34 ++++++++++++++++++= +++- .../selftests/coredump/coredump_test_helpers.c | 3 +- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/fs/coredump.c b/fs/coredump.c index 364c89c5f82a..bdf2eae948d0 100644 --- a/fs/coredump.c +++ b/fs/coredump.c @@ -799,7 +799,7 @@ static bool coredump_sock_request(struct core_name *cn,= struct coredump_params * .size =3D sizeof(struct coredump_req), .mask =3D COREDUMP_KERNEL | COREDUMP_USERSPACE | COREDUMP_REJECT | COREDUMP_WAIT | - COREDUMP_HEADER, + COREDUMP_HEADER | COREDUMP_SPARSE, .size_ack =3D sizeof(struct coredump_ack), }; struct coredump_ack ack =3D {}; @@ -854,6 +854,12 @@ static bool coredump_sock_request(struct core_name *cn= , struct coredump_params * return false; } =20 + /* Zero frames only exist inside a framed stream. */ + if ((ack.mask & COREDUMP_SPARSE) && !(ack.mask & COREDUMP_HEADER)) { + coredump_sock_mark(cprm->file, COREDUMP_MARK_CONFLICTING); + return false; + } + if (ack.spare) { coredump_sock_mark(cprm->file, COREDUMP_MARK_UNSUPPORTED); return false; @@ -1229,6 +1235,11 @@ static bool dump_framed(const struct coredump_params= *cprm) return cprm->mask & COREDUMP_HEADER; } =20 +static bool dump_sparse(const struct coredump_params *cprm) +{ + return cprm->mask & COREDUMP_SPARSE; +} + /* Describe the next @len bytes of the coredump. Returns the header size. = */ static size_t dump_frame_init(struct coredump_params *cprm, enum coredump_frame_type type, u64 len) @@ -1292,11 +1303,32 @@ static int __dump_emit(struct coredump_params *cprm= , const void *addr, int nr) return dump_write_iter(cprm, &iter, nr); } =20 +/* Hand the server the length of the hole instead of the hole itself. */ +static int dump_skip_frame(struct coredump_params *cprm, size_t nr) +{ + struct kvec kvec; + struct iov_iter iter; + size_t hdr; + + if (dump_interrupted()) + return 0; + + hdr =3D dump_frame_init(cprm, COREDUMP_FRAME_ZERO, nr); + kvec.iov_base =3D cprm->frame; + kvec.iov_len =3D hdr; + iov_iter_kvec(&iter, ITER_SOURCE, &kvec, 1, hdr); + + return dump_write_iter(cprm, &iter, nr); +} + static int __dump_skip(struct coredump_params *cprm, size_t nr) { static char zeroes[PAGE_SIZE]; struct file *file =3D cprm->file; =20 + if (dump_sparse(cprm)) + return dump_skip_frame(cprm, nr); + if (file->f_mode & FMODE_LSEEK) { if (dump_interrupted() || vfs_llseek(file, nr, SEEK_CUR) < 0) return 0; diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/too= ls/testing/selftests/coredump/coredump_test_helpers.c index bfe10bc51618..ee669969605b 100644 --- a/tools/testing/selftests/coredump/coredump_test_helpers.c +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c @@ -290,7 +290,8 @@ bool send_coredump_ack(int fd, const struct coredump_re= q *req, /* Every option the kernel is expected to advertise in coredump_req->mask.= */ #define COREDUMP_REQ_MASK_ALL \ (COREDUMP_KERNEL | COREDUMP_USERSPACE | \ - COREDUMP_REJECT | COREDUMP_WAIT | COREDUMP_HEADER) + COREDUMP_REJECT | COREDUMP_WAIT | \ + COREDUMP_HEADER | COREDUMP_SPARSE) =20 bool check_coredump_req(const struct coredump_req *req) { --=20 2.53.0 From nobody Tue Sep 29 06:49:25 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E40593F3273; Tue, 11 Aug 2026 15:28:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462106; cv=none; b=kTn0Nzj7bGtbth8LfQRaQk20DpIqnryg8vN+j4U33qdxklxHynfZd+yAk29K7F7N1uuaQHVChJj/Gs8N+srmHUGQ/LaM7H5KWNcFawYglI7J3/6GGYhUUzQtt16hU/c1P8n1VbVd6ESc5NQsLJzaNDG71sA00M7ci/cGGD+OysU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1786462106; c=relaxed/simple; bh=CamofIBhXFoXZcBJPLKpcNj976NXj8B3BDgiDN4BT1k=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jCc1W6WR3D/R1i2OT9g5WFslSqmSvmKBaA/osmv0gzh4m7T9CFtb5rbLcUHJEWfpvgq8kvgwaXmhkX5NJq3DiJscJ+5kRC/5Y5PWFlkel2aLJyQ9kFyOf/B3v9NBMuN8goKwlslmLxW9V6CsqOVqHq2dWi4ZBRA9B2HnGENSmOU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=csZT+OQW; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="csZT+OQW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AA58B1F00A3A; Tue, 11 Aug 2026 15:28:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1786462104; bh=kMay+L1AYU36nG7IEiQytwVomvHtiRva+AboZzfmtms=; h=From:Date:Subject:References:In-Reply-To:To:Cc; b=csZT+OQWAYEJS5WyvDG1We6a4cCdwoH64dANf9Lmk5/fDy08lbGxdLJm5bmxyELDL DRUCJBXmDCirZ6GpBzUOE4wo38tH2IAeIQC2NJojo4roqBwbZMsHW6lmQNzozvuKx3 YQqOx/i+K6v3+f22p79LdD30SUiUjHPpb7TGaBNamopHfNLmRbnAb81B4pkcju9VwQ FkrC3Ui+Nr5mXX0xroSo/v7rYboxAKb6bUfc6y0k2Owwilsr08l9krTqsShrLMyE79 K+Yg62EnfiuBTbyqVa+SpfbwUQvYKqqKy3p/y+2MfPV1PrQFep8l3aTw743QZJjWZO CksEYuWvHa9Ew== From: Christian Brauner Date: Tue, 11 Aug 2026 17:27:32 +0200 Subject: [PATCH 11/11] selftests/coredump: test COREDUMP_HEADER and COREDUMP_SPARSE Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260811-work-coredump-sparse-v1-11-cd3e8b1e356d@kernel.org> References: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> In-Reply-To: <20260811-work-coredump-sparse-v1-0-cd3e8b1e356d@kernel.org> To: Jacob Lalonde , Josef Bacik Cc: Alexander Viro , Jan Kara , Andrew Morton , David Hildenbrand , Lorenzo Stoakes , "Liam R. Howlett" , Vlastimil Babka , Mike Rapoport , Suren Baghdasaryan , Michal Hocko , Omar Sandoval , Jacob Lalonde , Shuah Khan , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-mm@kvack.org, linux-kselftest@vger.kernel.org, "Christian Brauner (Amutable)" X-Mailer: b4 0.17-dev-362b8 X-Developer-Signature: v=1; a=openpgp-sha256; l=18037; i=brauner@kernel.org; h=from:subject:message-id; bh=CamofIBhXFoXZcBJPLKpcNj976NXj8B3BDgiDN4BT1k=; b=owGbwMvMwCU28Zj0gdSKO4sYT6slMWRV2yeetO6a95m95uCVgubPZe/DY/63OHyde0rmTP2uO uPOU88qO0pZGMS4GGTFFFkc2k3C5ZbzVGw2ytSAmcPKBDKEgYtTACbSMJuR4deZwPVPjPPnPhdu /ftdq+OZg83s+kdntsxcfdVfMW+XymqGf8p+qRO813Ikm0y7w/3x1d5ynpt7e43275f5/HTVo5v zf3MDAA== X-Developer-Key: i=brauner@kernel.org; a=openpgp; fpr=4880B8C9BD0E5106FC070F4F7B3C391EFEA93624 Test the new COREDUMP_HEADER and COREDUMP_SPARSE flags. Signed-off-by: Christian Brauner (Amutable) --- .../coredump/coredump_socket_protocol_test.c | 379 +++++++++++++++++= ++++ tools/testing/selftests/coredump/coredump_test.h | 6 + .../selftests/coredump/coredump_test_helpers.c | 156 ++++++++- 3 files changed, 540 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 60a357e628eb..ef36e787a529 100644 --- a/tools/testing/selftests/coredump/coredump_socket_protocol_test.c +++ b/tools/testing/selftests/coredump/coredump_socket_protocol_test.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 =20 +#include #include #include #include @@ -1573,4 +1574,382 @@ TEST_F_TIMEOUT(coredump, socket_multiple_crashing_c= oredumps_epoll_workers, 500) wait_and_check_coredump_server(pid_coredump_server, _metadata, self); } =20 +/* + * Reassemble a framed coredump and check that what comes out is an ELF + * core file. The frames themselves are validated by recv_coredump_frames(= ). + */ +TEST_F(coredump, socket_request_sparse) +{ + unsigned char ehdr[EI_NIDENT + sizeof(Elf64_Half)]; + int fd_core_file, pidfd, status; + pid_t pid, pid_coredump_server; + struct pidfd_info info =3D {}; + int ipc_sockets[2]; + Elf64_Half e_type; + struct stat st; + char c; + + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets)= , 0); + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); + + pid_coredump_server =3D fork(); + ASSERT_GE(pid_coredump_server, 0); + if (pid_coredump_server =3D=3D 0) { + int fd_server =3D -1, fd_coredump =3D -1, fd_peer_pidfd =3D -1; + int fd_file =3D -1; + int exit_code =3D EXIT_FAILURE; + struct coredump_req req =3D {}; + + close(ipc_sockets[0]); + + fd_server =3D 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 =3D accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); + if (fd_coredump < 0) + goto out; + + fd_peer_pidfd =3D get_peer_pidfd(fd_coredump); + if (fd_peer_pidfd < 0) + goto out; + + fd_file =3D creat("/tmp/coredump.file", 0644); + if (fd_file < 0) + goto out; + + if (!read_coredump_req(fd_coredump, &req)) + goto out; + + if (!check_coredump_req(&req)) + goto out; + + if (!send_coredump_ack(fd_coredump, &req, + COREDUMP_KERNEL | COREDUMP_HEADER | + COREDUMP_SPARSE | COREDUMP_WAIT, 0)) + goto out; + + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) + goto out; + + if (recv_coredump_frames(fd_coredump, fd_file, NULL) < 0) + goto out; + + exit_code =3D EXIT_SUCCESS; +out: + if (fd_file >=3D 0) + close(fd_file); + if (fd_peer_pidfd >=3D 0) + close(fd_peer_pidfd); + if (fd_coredump >=3D 0) + close(fd_coredump); + if (fd_server >=3D 0) + close(fd_server); + _exit(exit_code); + } + self->pid_coredump_server =3D pid_coredump_server; + + EXPECT_EQ(close(ipc_sockets[1]), 0); + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); + EXPECT_EQ(close(ipc_sockets[0]), 0); + + pid =3D fork(); + ASSERT_GE(pid, 0); + if (pid =3D=3D 0) + crashing_child(); + + pidfd =3D sys_pidfd_open(pid, 0); + ASSERT_GE(pidfd, 0); + + waitpid(pid, &status, 0); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_TRUE(WCOREDUMP(status)); + + 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); + + ASSERT_EQ(stat("/tmp/coredump.file", &st), 0); + ASSERT_GT(st.st_size, (off_t)sizeof(ehdr)); + + /* What the frames reassemble into has to be an ELF core file. */ + fd_core_file =3D open("/tmp/coredump.file", O_RDONLY | O_CLOEXEC); + ASSERT_GE(fd_core_file, 0); + ASSERT_EQ(read_nointr(fd_core_file, ehdr, sizeof(ehdr)), sizeof(ehdr)); + EXPECT_EQ(close(fd_core_file), 0); + + /* e_type sits right behind e_ident in both ELF32 and ELF64. */ + ASSERT_EQ(memcmp(ehdr, ELFMAG, SELFMAG), 0); + memcpy(&e_type, ehdr + EI_NIDENT, sizeof(e_type)); + ASSERT_EQ(e_type, ET_CORE); +} + +/* + * Crash a child with a mostly-unpopulated mapping and reassemble its + * framed coredump, reporting what crossed the socket and the coredump + * size the frames describe. + */ +static void test_framed_hole(struct __test_metadata *const _metadata, + FIXTURE_DATA(coredump) *self, __u64 ack_mask, + ssize_t *received, off_t *coredump_size) +{ + int pidfd, status; + pid_t pid, pid_coredump_server; + struct pidfd_info info =3D {}; + 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 =3D fork(); + ASSERT_GE(pid_coredump_server, 0); + if (pid_coredump_server =3D=3D 0) { + int fd_server =3D -1, fd_coredump =3D -1, fd_peer_pidfd =3D -1; + int fd_file =3D -1; + int exit_code =3D EXIT_FAILURE; + struct coredump_req req =3D {}; + off_t size =3D 0; + ssize_t ret; + + close(ipc_sockets[0]); + close(pipefds[0]); + + fd_server =3D 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 =3D accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); + if (fd_coredump < 0) + goto out; + + fd_peer_pidfd =3D 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 =3D 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; + + if (!send_coredump_ack(fd_coredump, &req, ack_mask, 0)) + goto out; + + if (!read_marker(fd_coredump, COREDUMP_MARK_REQACK)) + goto out; + + ret =3D recv_coredump_frames(fd_coredump, fd_file, &size); + if (ret < 0) + goto out; + + if (write_nointr(pipefds[1], &ret, sizeof(ret)) !=3D sizeof(ret)) + goto out; + if (write_nointr(pipefds[1], &size, sizeof(size)) !=3D sizeof(size)) + goto out; + + exit_code =3D EXIT_SUCCESS; +out: + close(pipefds[1]); + if (fd_file >=3D 0) + close(fd_file); + if (fd_peer_pidfd >=3D 0) + close(fd_peer_pidfd); + if (fd_coredump >=3D 0) + close(fd_coredump); + if (fd_server >=3D 0) + close(fd_server); + _exit(exit_code); + } + self->pid_coredump_server =3D 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 =3D fork(); + ASSERT_GE(pid, 0); + if (pid =3D=3D 0) + crashing_child_sparse(SPARSE_MAPPING_SIZE); + + pidfd =3D sys_pidfd_open(pid, 0); + ASSERT_GE(pidfd, 0); + + waitpid(pid, &status, 0); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_TRUE(WCOREDUMP(status)); + + ASSERT_TRUE(get_pidfd_info(pidfd, &info)); + ASSERT_GT((info.mask & PIDFD_INFO_COREDUMP), 0); + ASSERT_GT((info.coredump_mask & PIDFD_COREDUMPED), 0); + + ASSERT_EQ(read_nointr(pipefds[0], received, sizeof(*received)), + sizeof(*received)); + ASSERT_EQ(read_nointr(pipefds[0], coredump_size, sizeof(*coredump_size)), + sizeof(*coredump_size)); + EXPECT_EQ(close(pipefds[0]), 0); + + wait_and_check_coredump_server(pid_coredump_server, _metadata, self); + + /* The mapping is in the coredump, holes included. */ + ASSERT_GT(*coredump_size, (off_t)SPARSE_MAPPING_SIZE); +} + +/* + * A mapping that has been written to is dumped whole, including the parts + * of it that were never faulted in. With COREDUMP_SPARSE the holes stay + * off the wire. + */ +TEST_F(coredump, socket_request_sparse_hole) +{ + off_t coredump_size =3D 0; + ssize_t received =3D 0; + + test_framed_hole(_metadata, self, + COREDUMP_KERNEL | COREDUMP_HEADER | + COREDUMP_SPARSE | COREDUMP_WAIT, + &received, &coredump_size); + + /* The holes didn't have to go over the socket. */ + ASSERT_LT(received, coredump_size / 8); +} + +/* + * COREDUMP_HEADER alone frames the stream but elides nothing: the holes + * cross the socket as data frames. + */ +TEST_F(coredump, socket_request_header_hole) +{ + off_t coredump_size =3D 0; + ssize_t received =3D 0; + + test_framed_hole(_metadata, self, + COREDUMP_KERNEL | COREDUMP_HEADER | COREDUMP_WAIT, + &received, &coredump_size); + + /* Framing alone elides nothing, so everything crossed the socket. */ + ASSERT_GT(received, coredump_size); +} + +/* Ack @ack_mask, expect the kernel to refuse it as conflicting. */ +static void test_conflicting_ack(struct __test_metadata *const _metadata, + FIXTURE_DATA(coredump) *self, __u64 ack_mask) +{ + int pidfd, status; + pid_t pid, pid_coredump_server; + struct pidfd_info info =3D {}; + int ipc_sockets[2]; + char c; + + ASSERT_EQ(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, ipc_sockets)= , 0); + ASSERT_TRUE(set_core_pattern("@@/tmp/coredump.socket")); + + pid_coredump_server =3D fork(); + ASSERT_GE(pid_coredump_server, 0); + if (pid_coredump_server =3D=3D 0) { + int fd_server =3D -1, fd_coredump =3D -1, fd_peer_pidfd =3D -1; + int exit_code =3D EXIT_FAILURE; + struct coredump_req req =3D {}; + + close(ipc_sockets[0]); + + fd_server =3D 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 =3D accept4(fd_server, NULL, NULL, SOCK_CLOEXEC); + if (fd_coredump < 0) + goto out; + + fd_peer_pidfd =3D get_peer_pidfd(fd_coredump); + if (fd_peer_pidfd < 0) + goto out; + + if (!read_coredump_req(fd_coredump, &req)) + goto out; + + if (!check_coredump_req(&req)) + goto out; + + if (!send_coredump_ack(fd_coredump, &req, ack_mask, 0)) + goto out; + + if (!read_marker(fd_coredump, COREDUMP_MARK_CONFLICTING)) + goto out; + + exit_code =3D EXIT_SUCCESS; +out: + if (fd_peer_pidfd >=3D 0) + close(fd_peer_pidfd); + if (fd_coredump >=3D 0) + close(fd_coredump); + if (fd_server >=3D 0) + close(fd_server); + _exit(exit_code); + } + self->pid_coredump_server =3D pid_coredump_server; + + EXPECT_EQ(close(ipc_sockets[1]), 0); + ASSERT_EQ(read_nointr(ipc_sockets[0], &c, 1), 1); + EXPECT_EQ(close(ipc_sockets[0]), 0); + + pid =3D fork(); + ASSERT_GE(pid, 0); + if (pid =3D=3D 0) + crashing_child(); + + pidfd =3D sys_pidfd_open(pid, 0); + ASSERT_GE(pidfd, 0); + + waitpid(pid, &status, 0); + ASSERT_TRUE(WIFSIGNALED(status)); + ASSERT_FALSE(WCOREDUMP(status)); + + 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); +} + +/* COREDUMP_HEADER frames a coredump the kernel writes, nothing else. */ +TEST_F(coredump, socket_request_header_without_kernel) +{ + test_conflicting_ack(_metadata, self, COREDUMP_USERSPACE | COREDUMP_HEADE= R); +} + +/* A zero frame can't exist outside a framed stream. */ +TEST_F(coredump, socket_request_sparse_without_header) +{ + test_conflicting_ack(_metadata, self, COREDUMP_KERNEL | COREDUMP_SPARSE); +} + TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/coredump/coredump_test.h b/tools/testi= ng/selftests/coredump/coredump_test.h index a02809145e2d..ae1751298aaf 100644 --- a/tools/testing/selftests/coredump/coredump_test.h +++ b/tools/testing/selftests/coredump/coredump_test.h @@ -16,6 +16,9 @@ =20 #define NUM_THREAD_SPAWN 128 =20 +/* Size of the mostly unpopulated mapping the sparse coredump test maps. */ +#define SPARSE_MAPPING_SIZE (256 * 1024 * 1024) + /* Coredump fixture */ FIXTURE(coredump) { @@ -27,6 +30,9 @@ FIXTURE(coredump) /* Shared helper function declarations */ void *do_nothing(void *arg); void crashing_child(void); +void crashing_child_sparse(size_t size); +ssize_t recv_coredump_frames(int fd_coredump, int fd_core_file, + off_t *coredump_size); int create_detached_tmpfs(void); int create_and_listen_unix_socket(const char *path); bool set_core_pattern(const char *pattern); diff --git a/tools/testing/selftests/coredump/coredump_test_helpers.c b/too= ls/testing/selftests/coredump/coredump_test_helpers.c index ee669969605b..dececebe15cb 100644 --- a/tools/testing/selftests/coredump/coredump_test_helpers.c +++ b/tools/testing/selftests/coredump/coredump_test_helpers.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,156 @@ void crashing_child(void) i =3D *(volatile int *)NULL; } =20 +void crashing_child_sparse(size_t size) +{ + char *p; + + /* + * Touch the first page only. The whole mapping is dumped because + * it has been written to, but all of it save that one page is a + * hole. + */ + p =3D mmap(NULL, size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); + if (p !=3D MAP_FAILED) + p[0] =3D 'x'; + + /* crash on purpose */ + *(volatile int *)NULL =3D 0; +} + +/* Read @len bytes off the socket, writing them at @offset if @fd_out >=3D= 0. */ +static ssize_t recv_frame_bytes(int fd_coredump, __u64 len, int fd_out, + off_t offset) +{ + ssize_t received =3D 0; + + while (len) { + char buffer[PAGE_SIZE]; + size_t chunk =3D len < sizeof(buffer) ? len : sizeof(buffer); + ssize_t ret; + + ret =3D recv(fd_coredump, buffer, chunk, MSG_WAITALL); + if (ret <=3D 0) { + fprintf(stderr, "%s: short read %zd: %m\n", + __func__, ret); + return -1; + } + + if (fd_out >=3D 0 && + pwrite(fd_out, buffer, ret, offset + received) !=3D ret) { + fprintf(stderr, "%s: pwrite failed: %m\n", __func__); + return -1; + } + + received +=3D ret; + len -=3D ret; + } + + return received; +} + +ssize_t recv_coredump_frames(int fd_coredump, int fd_core_file, + off_t *coredump_size) +{ + ssize_t received =3D 0; + off_t size =3D 0; + + for (;;) { + struct coredump_frame_header frame =3D {}; + size_t known; + ssize_t ret; + + /* Peek the header size the way read_coredump_req() does. */ + ret =3D recv(fd_coredump, &frame, sizeof(frame.size), + MSG_PEEK | MSG_WAITALL); + if (ret =3D=3D 0) + break; + if (ret !=3D sizeof(frame.size)) { + fprintf(stderr, "%s: short frame peek %zd: %m\n", + __func__, ret); + return -1; + } + + if (frame.size < COREDUMP_FRAME_HEADER_SIZE_VER0) { + fprintf(stderr, "%s: header size %u below minimum %u\n", + __func__, frame.size, + COREDUMP_FRAME_HEADER_SIZE_VER0); + return -1; + } + + /* Consume as much of the header as we know about. */ + known =3D frame.size < sizeof(frame) ? frame.size : sizeof(frame); + ret =3D recv(fd_coredump, &frame, known, MSG_WAITALL); + if (ret !=3D (ssize_t)known) { + fprintf(stderr, "%s: short frame read %zd: %m\n", + __func__, ret); + return -1; + } + received +=3D ret; + + /* + * A flag changes what the frame means, so refuse one we + * don't know rather than guess. + */ + if (frame.flags) { + fprintf(stderr, "%s: unknown header flags 0x%llx\n", + __func__, (unsigned long long)frame.flags); + return -1; + } + + /* Discard any part of the header we have no use for. */ + ret =3D recv_frame_bytes(fd_coredump, frame.size - known, -1, 0); + if (ret < 0) + return -1; + received +=3D ret; + + /* Frames are sent in order and they don't leave gaps. */ + if (frame.offset !=3D (__u64)size) { + fprintf(stderr, "%s: frame at %llu, expected %llu\n", + __func__, (unsigned long long)frame.offset, + (unsigned long long)size); + return -1; + } + + switch (frame.type) { + case COREDUMP_FRAME_ZERO: + /* A hole. It comes with no data and needs none. */ + break; + case COREDUMP_FRAME_DATA: + ret =3D recv_frame_bytes(fd_coredump, frame.len, + fd_core_file, size); + if (ret < 0) + return -1; + received +=3D ret; + break; + default: + fprintf(stderr, "%s: unknown frame type %u\n", + __func__, frame.type); + return -1; + } + + size +=3D frame.len; + } + + /* + * Nothing is written for a hole, so grow the file to the size the + * frames describe in case the coredump ended in one. + */ + if (ftruncate(fd_core_file, size) < 0) { + fprintf(stderr, "%s: ftruncate to %llu failed: %m\n", + __func__, (unsigned long long)size); + return -1; + } + + if (coredump_size) + *coredump_size =3D size; + + fprintf(stderr, "Received %zd bytes for a coredump of %llu bytes\n", + received, (unsigned long long)size); + return received; +} + int create_detached_tmpfs(void) { int fd_context, fd_tmpfs; @@ -101,6 +252,7 @@ int create_and_listen_unix_socket(const char *path) return fd; =20 out: + fprintf(stderr, "%s: %s: %m\n", __func__, path); if (fd >=3D 0) close(fd); return -1; @@ -279,8 +431,10 @@ bool send_coredump_ack(int fd, const struct coredump_r= eq *req, large_ack.ack.mask =3D mask; large_ack.ack.size =3D size_ack; ret =3D send(fd, &large_ack, size_ack, MSG_NOSIGNAL); - if (ret !=3D size_ack) + if (ret !=3D size_ack) { + fprintf(stderr, "%s: short send %zd: %m\n", __func__, ret); return false; + } =20 fprintf(stderr, "Sent coredump ack with size %zu and mask 0x%llx\n", size_ack, (unsigned long long)mask); --=20 2.53.0