From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from firstgate.proxmox.com (firstgate.proxmox.com [IPv6:2a01:7e0:0:424::9]) by lore.proxmox.com (Postfix) with ESMTPS id 072E21FF13F for ; Thu, 26 Feb 2026 13:32:49 +0100 (CET) Received: from firstgate.proxmox.com (localhost [127.0.0.1]) by firstgate.proxmox.com (Proxmox) with ESMTP id 530A61F12A; Thu, 26 Feb 2026 13:33:35 +0100 (CET) From: Markus Ebner To: pve-devel@lists.proxmox.com Subject: [PATCH qemu-server v3 1/3] agent: file-read: Allow specifying max number of bytes to read Date: Thu, 26 Feb 2026 13:31:17 +0100 Message-ID: <20260226123122.60418-2-info@ebner-markus.de> In-Reply-To: <20260226123122.60418-1-info@ebner-markus.de> References: <20260226123122.60418-1-info@ebner-markus.de> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-SPAM-LEVEL: Spam detection results: 0 AWL 0.582 Adjusted score from AWL reputation of From: address BAYES_00 -1.9 Bayes spam probability is 0 to 1% DMARC_PASS -0.1 DMARC pass policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record X-MailFrom: info@ebner-markus.de X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation Message-ID-Hash: SF5HTFLRPU3NCDGD62LHNFZ5JCSYBCTH X-Message-ID-Hash: SF5HTFLRPU3NCDGD62LHNFZ5JCSYBCTH X-Mailman-Approved-At: Thu, 26 Feb 2026 13:33:38 +0100 CC: Markus Ebner X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: The previous file-read implementation in the Proxmox API always attempted to read a fixed 16 MiB. On busy or resource-constrainted hosts, that often caused request timeouts, with no option to reduce the number of read bytes to at least read something. The new parameter count now allows specifying the exact number of bytes that should be read from the given file. To be backwards compatible with the previous behavior, it defaults to 16 MiB. These 16 MiB are further also the maximum allowed value. Signed-off-by: Markus Ebner --- src/PVE/API2/Qemu/Agent.pm | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/PVE/API2/Qemu/Agent.pm b/src/PVE/API2/Qemu/Agent.pm index de36ce1e..c6155f02 100644 --- a/src/PVE/API2/Qemu/Agent.pm +++ b/src/PVE/API2/Qemu/Agent.pm @@ -464,6 +464,14 @@ __PACKAGE__->register_method({ 'pve-vmid', { completion => \&PVE::QemuServer::complete_vmid_running }, ), + count => { + type => 'integer', + optional => 1, + minimum => 1, + maximum => $MAX_READ_SIZE, + default => $MAX_READ_SIZE, + description => "Number of bytes to read.", + }, file => { type => 'string', description => 'The path to the file', @@ -481,12 +489,13 @@ __PACKAGE__->register_method({ truncated => { type => 'boolean', optional => 1, - description => "If set to 1, the output is truncated and not complete", + description => "If set to 1, the read did not reach the end of the file.", }, }, }, code => sub { my ($param) = @_; + my $count = $param->{count} // $MAX_READ_SIZE; my $vmid = $param->{vmid}; my $conf = PVE::QemuConfig->load_config($vmid); @@ -494,18 +503,20 @@ __PACKAGE__->register_method({ my $qgafh = agent_cmd($vmid, $conf, "file-open", { path => $param->{file} }, "can't open file"); - my $bytes_left = $MAX_READ_SIZE; + my $bytes_read = 0; my $eof = 0; my $read_size = 1024 * 1024; my $content = ""; - while ($bytes_left > 0 && !$eof) { + while ($bytes_read < $count && !$eof) { + my $bytes_left = $count - $bytes_read; + my $chunk_size = $bytes_left < $read_size ? $bytes_left : $read_size; my $read = - mon_cmd($vmid, "guest-file-read", handle => $qgafh, count => int($read_size)); + mon_cmd($vmid, "guest-file-read", handle => $qgafh, count => int($chunk_size)); check_agent_error($read, "can't read from file"); $content .= decode_base64($read->{'buf-b64'}); - $bytes_left -= $read->{count}; + $bytes_read += $read->{count}; $eof = $read->{eof} // 0; } @@ -514,12 +525,14 @@ __PACKAGE__->register_method({ my $result = { content => $content, - 'bytes-read' => ($MAX_READ_SIZE - $bytes_left), + 'bytes-read' => $bytes_read, }; if (!$eof) { - warn - "agent file-read: reached maximum read size: $MAX_READ_SIZE bytes. output might be truncated.\n"; + if (!defined($param->{count})) { + warn "agent file-read: reached maximum read size: $MAX_READ_SIZE bytes." + . " output might be truncated.\n"; + } $result->{truncated} = 1; } -- 2.53.0