[PATCHv7 06/13] kexec_file: Chain the stages into a pipeline

Pingfan Liu piliu at redhat.com
Sat Mar 21 18:43:55 PDT 2026


Images may consist of multiple layers, each with a distinct format. For
example, an AArch64 UKI image typically embeds a zboot image in the
.linux section. The parser therefore determines whether its output
should be forwarded to the next stage.

Intermediate results are stored in next_parsing_buf and then promoted to
parsing_buf for the subsequent stage.

Signed-off-by: Pingfan Liu <piliu at redhat.com>
Cc: Baoquan He <bhe at redhat.com>
Cc: Dave Young <dyoung at redhat.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Philipp Rudo <prudo at redhat.com>
To: kexec at lists.infradead.org
---
 kernel/kexec_bpf_loader.c | 47 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 46 insertions(+), 1 deletion(-)

diff --git a/kernel/kexec_bpf_loader.c b/kernel/kexec_bpf_loader.c
index af16f7b685d9a..7f7884411e2c7 100644
--- a/kernel/kexec_bpf_loader.c
+++ b/kernel/kexec_bpf_loader.c
@@ -41,6 +41,8 @@ struct kexec_context {
 	bool parsed;
 	char *parsing_buf[MAX_PARSING_BUF_NUM];
 	unsigned long parsing_buf_sz[MAX_PARSING_BUF_NUM];
+	char *next_parsing_buf[MAX_PARSING_BUF_NUM];
+	unsigned long next_parsing_buf_sz[MAX_PARSING_BUF_NUM];
 
 	char *kernel;
 	unsigned long kernel_sz;
@@ -278,8 +280,9 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
 	struct bpf_parser_buf *pbuf = parser->buf;
 	struct kexec_context *ctx = (struct kexec_context *)parser->data;
 	struct cmd_hdr *cmd = (struct cmd_hdr *)pbuf->buf;
-	char *decompressed_buf, *buf, *p;
+	char *decompressed_buf, *buf, *p, *pn;
 	unsigned long decompressed_sz;
+	bool fill_pipeline = false;
 	int ret = 0;
 
 	buf = pbuf->buf + sizeof(struct cmd_hdr);
@@ -288,6 +291,7 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
 				cmd->payload_len, pbuf->size);
 		return -EINVAL;
 	}
+	fill_pipeline = cmd->pipeline_flag & KEXEC_BPF_PIPELINE_FILL;
 	switch (cmd->cmd) {
 	case KEXEC_BPF_CMD_DONE:
 		ctx->parsed = true;
@@ -301,6 +305,23 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
 				vfree(ctx->kernel);
 				ctx->kernel = decompressed_buf;
 				ctx->kernel_sz = decompressed_sz;
+				if (fill_pipeline) {
+					int i;
+
+					for (i = 0; i < MAX_PARSING_BUF_NUM; i++) {
+						if (ctx->next_parsing_buf[i])
+							continue;
+						ctx->next_parsing_buf[i] = decompressed_buf;
+						ctx->next_parsing_buf_sz[i] = decompressed_sz;
+						break;
+					}
+					/* No enough parsing slot */
+					if (i == MAX_PARSING_BUF_NUM) {
+						ctx->kernel = NULL;
+						vfree(decompressed_buf);
+						return -ENOMEM;
+					}
+				}
 				break;
 			default:
 				vfree(decompressed_buf);
@@ -313,6 +334,22 @@ static int kexec_buff_parser(struct bpf_parser_context *parser)
 		if (!p)
 			return -ENOMEM;
 		memcpy(p, buf, cmd->payload_len);
+		if (fill_pipeline) {
+			pn = __vmalloc(cmd->payload_len, GFP_KERNEL | __GFP_ACCOUNT);
+			if (!pn) {
+				vfree(p);
+				return -ENOMEM;
+			}
+			memcpy(pn, buf, cmd->payload_len);
+			for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
+				if (!ctx->next_parsing_buf[i]) {
+					ctx->next_parsing_buf[i] = pn;
+					ctx->next_parsing_buf_sz[i] = cmd->payload_len;
+					break;
+				}
+			}
+		}
+
 		switch (cmd->subcmd) {
 		case KEXEC_BPF_SUBCMD_KERNEL:
 			vfree(ctx->kernel);
@@ -637,6 +674,14 @@ static int process_bpf_parsers_container(const char *elf_buf, size_t elf_sz,
 			context->parsing_buf[i] = NULL;
 			context->parsing_buf_sz[i] = 0;
 		}
+		for (int i = 0; i < MAX_PARSING_BUF_NUM; i++) {
+			if (!context->next_parsing_buf[i])
+				break;
+			context->parsing_buf[i] = context->next_parsing_buf[i];
+			context->parsing_buf_sz[i] = context->next_parsing_buf_sz[i];
+			context->next_parsing_buf[i] = NULL;
+			context->next_parsing_buf_sz[i] = 0;
+		}
 
 		put_bpf_parser_context(bpf);
 		/* If the bpf-prog success, it flags by KEXEC_BPF_CMD_DONE */
-- 
2.49.0




More information about the kexec mailing list