Compare commits
6 commits
be6264ebbf
...
503ae6d680
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
503ae6d680 | ||
|
|
a775287ee5 | ||
|
|
21768f8732 | ||
|
|
1ef49d7295 | ||
|
|
1bcc5a6abf | ||
|
|
68c0855d8f |
10 changed files with 291 additions and 1 deletions
|
|
@ -5822,6 +5822,28 @@ sub vm_start_nolock {
|
|||
warn $@ if $@;
|
||||
}
|
||||
|
||||
# set write threshold for LVM thin provisioning disks
|
||||
PVE::QemuConfig->foreach_volume(
|
||||
$conf,
|
||||
sub {
|
||||
my ($ds, $drive) = @_;
|
||||
return if PVE::QemuServer::drive_is_cdrom($drive, 1);
|
||||
my $volid = $drive->{file};
|
||||
if ( $volid ne 'none') {
|
||||
my $extra_blockdev_options = {};
|
||||
# $extra_blockdev_options->{'live-restore'} = $live_restore if $live_restore;
|
||||
# extra protection for templates, but SATA and IDE don't support it..
|
||||
$extra_blockdev_options->{'read-only'} = 1
|
||||
if drive_is_read_only($conf, $drive);
|
||||
|
||||
my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive);
|
||||
PVE::QemuServer::Blockdev::set_write_threshold(
|
||||
$storecfg, $vmid, $drive_id, $volid, $extra_blockdev_options,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
#start nbd server for storage migration
|
||||
if (my $nbd = $migrate_opts->{nbd}) {
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ use PVE::QemuServer::Drive qw(drive_is_cdrom);
|
|||
use PVE::QemuServer::Helpers;
|
||||
use PVE::QemuServer::Machine;
|
||||
use PVE::QemuServer::Monitor qw(mon_cmd);
|
||||
use PVE::SafeSyslog;
|
||||
|
||||
# gives ($host, $port, $export)
|
||||
my $NBD_TCP_PATH_RE_3 = qr/nbd:(\S+):(\d+):exportname=(\S+)/;
|
||||
|
|
@ -111,6 +112,21 @@ sub get_block_info {
|
|||
return $block_info;
|
||||
}
|
||||
|
||||
sub get_block_stats {
|
||||
my ($vmid) = @_;
|
||||
|
||||
my $block_stats = {};
|
||||
|
||||
my $qmp_block_stats = mon_cmd($vmid, "query-blockstats");
|
||||
for my $info ($qmp_block_stats->@*) {
|
||||
my $qdev_id = $info->{qdev} or next;
|
||||
my $drive_id = qdev_id_to_drive_id($qdev_id);
|
||||
$block_stats->{$drive_id} = $info;
|
||||
}
|
||||
|
||||
return $block_stats;
|
||||
}
|
||||
|
||||
my sub get_node_name {
|
||||
my ($type, $drive_id, $volid, $options) = @_;
|
||||
|
||||
|
|
@ -700,6 +716,22 @@ sub resize {
|
|||
);
|
||||
}
|
||||
|
||||
sub underlay_resize {
|
||||
my ($storecfg, $vmid, $drive_id, $volid) = @_;
|
||||
|
||||
my $running = PVE::QemuServer::Helpers::vm_running_locally($vmid);
|
||||
|
||||
my $size = PVE::Storage::volume_underlay_resize($storecfg, $volid);
|
||||
syslog("info", "got size $size KiB\n");
|
||||
|
||||
return if !$running;
|
||||
my $block_info = get_block_info($vmid);
|
||||
my $inserted = $block_info->{$drive_id}->{inserted}
|
||||
or die "no block node inserted for drive '$drive_id'\n";
|
||||
|
||||
set_write_threshold($storecfg, $vmid, $drive_id, $volid);
|
||||
}
|
||||
|
||||
my sub blockdev_change_medium {
|
||||
my ($storecfg, $vmid, $qdev_id, $drive) = @_;
|
||||
|
||||
|
|
@ -820,6 +852,59 @@ sub set_io_throttle {
|
|||
}
|
||||
}
|
||||
|
||||
sub block_set_write_threshold {
|
||||
my ($vmid, $nodename, $threshold) = @_;
|
||||
|
||||
print "set threshold $nodename $threshold\n";
|
||||
|
||||
PVE::QemuServer::mon_cmd(
|
||||
$vmid,
|
||||
"block-set-write-threshold",
|
||||
'node-name' => $nodename,
|
||||
'write-threshold' => int($threshold),
|
||||
);
|
||||
}
|
||||
|
||||
sub compute_write_threshold {
|
||||
my ($storecfg, $volid) = @_;
|
||||
|
||||
my $lv_size = PVE::Storage::volume_underlay_size_info($storecfg, $volid, 5);
|
||||
|
||||
# FIX: change these vars to config inputs
|
||||
my $chunksize = 1024 * 1024 * 1024; # 1 GiB
|
||||
my $alert_chunk_percentage = 0.5; # alert when percetage of chunk used
|
||||
|
||||
my $write_threshold = $lv_size - $chunksize * (1 - $alert_chunk_percentage);
|
||||
|
||||
return $write_threshold;
|
||||
}
|
||||
|
||||
sub set_write_threshold {
|
||||
my ($storecfg, $vmid, $drive_id, $volid, $options) = @_;
|
||||
|
||||
my ($storeid) = PVE::Storage::parse_volume_id($volid);
|
||||
my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
|
||||
my $support_qemu_snapshots = PVE::Storage::volume_qemu_snapshot_method($storecfg, $volid);
|
||||
|
||||
# set write threshold is only supported for lvm storage using
|
||||
# qcow2+external snapshots
|
||||
return if $scfg->{type} ne 'lvm' || $support_qemu_snapshots ne 'mixed';
|
||||
# return if drive is not set as thin
|
||||
# return if !$drive->{thin};
|
||||
|
||||
print "setting threshold for $volid from $storeid\n";
|
||||
|
||||
my $snapshots = PVE::Storage::volume_snapshot_info($storecfg, $volid);
|
||||
my $parentid = $snapshots->{'current'}->{parent};
|
||||
# for now only set write_threshold for volumes that have snapshots
|
||||
if ($parentid) {
|
||||
my $nodename = get_node_name('file', $drive_id, $volid, $options);
|
||||
my $write_threshold = compute_write_threshold($storecfg, $volid);
|
||||
|
||||
block_set_write_threshold($vmid, $nodename, $write_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
sub blockdev_external_snapshot {
|
||||
my ($storecfg, $vmid, $machine_version, $deviceid, $drive, $snap, $parent_snap) = @_;
|
||||
|
||||
|
|
@ -868,6 +953,9 @@ sub blockdev_external_snapshot {
|
|||
node => $snap_fmt_blockdev->{'node-name'},
|
||||
overlay => $new_fmt_blockdev->{'node-name'},
|
||||
);
|
||||
|
||||
my $drive_id = PVE::QemuServer::Drive::get_drive_id($drive);
|
||||
set_write_threshold($storecfg, $vmid, $drive_id, $volid);
|
||||
}
|
||||
|
||||
sub blockdev_delete {
|
||||
|
|
|
|||
|
|
@ -254,6 +254,13 @@ my %drivedesc_base = (
|
|||
optional => 1,
|
||||
default => 0,
|
||||
},
|
||||
thin => {
|
||||
type => 'boolean',
|
||||
description =>
|
||||
'Controls whether a drive should be thin provisioned',
|
||||
optional => 1,
|
||||
default => 0,
|
||||
},
|
||||
);
|
||||
|
||||
my %iothread_fmt = (
|
||||
|
|
|
|||
8
src/qmeventd/docinfo.xml
Normal file
8
src/qmeventd/docinfo.xml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<!-- DocBook document information file for Proxmox VE asciidoc docs -->
|
||||
|
||||
<authorgroup>
|
||||
<corpauthor>Proxmox Server Solutions Gmbh
|
||||
<ulink url="https://www.proxmox.com/"><citetitle>www.proxmox.com</citetitle></ulink>
|
||||
</corpauthor>
|
||||
</authorgroup>
|
||||
|
||||
18
src/qmeventd/pve-copyright.adoc
Normal file
18
src/qmeventd/pve-copyright.adoc
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
Copyright and Disclaimer
|
||||
------------------------
|
||||
|
||||
Copyright (C) 2007-2022 Proxmox Server Solutions GmbH
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as
|
||||
published by the Free Software Foundation, either version 3 of the
|
||||
License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public
|
||||
License along with this program. If not, see
|
||||
https://www.gnu.org/licenses/
|
||||
BIN
src/qmeventd/qmeventd
Executable file
BIN
src/qmeventd/qmeventd
Executable file
Binary file not shown.
80
src/qmeventd/qmeventd.8
Normal file
80
src/qmeventd/qmeventd.8
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
'\" t
|
||||
.\" Title: qmeventd
|
||||
.\" Author: Proxmox Server Solutions Gmbh \m[blue]\fBwww.proxmox.com\fR\m[]
|
||||
.\" Generator: DocBook XSL Stylesheets vsnapshot <http://docbook.sf.net/>
|
||||
.\" Date: Fri Aug 15 05:33:35 PM WEST 2025
|
||||
.\" Manual: Proxmox VE Documentation
|
||||
.\" Source: \ \& 9.0.8
|
||||
.\" Language: English
|
||||
.\"
|
||||
.TH "QMEVENTD" "8" "Fri Aug 15 05:33:35 PM WEST 2025" "\ \& 9\&.0\&.8" "Proxmox VE Documentation"
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * Define some portability stuff
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.\" http://bugs.debian.org/507673
|
||||
.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
|
||||
.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
.ie \n(.g .ds Aq \(aq
|
||||
.el .ds Aq '
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * set default formatting
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" disable hyphenation
|
||||
.nh
|
||||
.\" disable justification (adjust text to left margin only)
|
||||
.ad l
|
||||
.\" -----------------------------------------------------------------
|
||||
.\" * MAIN CONTENT STARTS HERE *
|
||||
.\" -----------------------------------------------------------------
|
||||
.SH "NAME"
|
||||
qmeventd \- PVE QEMU Eventd Daemon
|
||||
.SH "SYNOPSIS"
|
||||
.sp
|
||||
\fBqmeventd\fR [\-f] [\-v] PATH
|
||||
.PP
|
||||
\-v
|
||||
.RS 4
|
||||
Turn on verbose messages
|
||||
.RE
|
||||
.PP
|
||||
\-f
|
||||
.RS 4
|
||||
Do not daemonize server
|
||||
.RE
|
||||
.PP
|
||||
PATH
|
||||
.RS 4
|
||||
The path to listen on
|
||||
.RE
|
||||
.sp
|
||||
This service is usually started and managed using systemd toolset\&. The service is called \fIqmeventd\fR\&.
|
||||
.sp
|
||||
.nf
|
||||
systemctl start qmeventd
|
||||
.fi
|
||||
.sp
|
||||
.nf
|
||||
systemctl stop qmeventd
|
||||
.fi
|
||||
.sp
|
||||
.nf
|
||||
systemctl status qmeventd
|
||||
.fi
|
||||
.SH "DESCRIPTION"
|
||||
.sp
|
||||
qmeventd is a daemon that listens on PATH for incoming connections from a qemu qmp socket, and waits for SHUTDOWN events\&. When a client then disconnects, it executes /usr/sbin/qm cleanup\&. This makes it easy to clean up leftover tap devices, vgpus, etc\&.
|
||||
.SH "COPYRIGHT AND DISCLAIMER"
|
||||
.sp
|
||||
Copyright \(co 2007\-2022 Proxmox Server Solutions GmbH
|
||||
.sp
|
||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version\&.
|
||||
.sp
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE\&. See the GNU Affero General Public License for more details\&.
|
||||
.sp
|
||||
You should have received a copy of the GNU Affero General Public License along with this program\&. If not, see \m[blue]\fBhttps://www\&.gnu\&.org/licenses/\fR\m[]
|
||||
.SH "AUTHOR"
|
||||
.PP
|
||||
\fBProxmox Server Solutions Gmbh
|
||||
\fR\fB\m[blue]\fBwww\&.proxmox\&.com\fR\m[]\fR\fB
|
||||
\fR
|
||||
16
src/qmeventd/qmeventd.8-synopsis.adoc
Normal file
16
src/qmeventd/qmeventd.8-synopsis.adoc
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
*qmeventd* `[-f]` `[-v]` `PATH`
|
||||
|
||||
`-v`:: Turn on verbose messages
|
||||
|
||||
`-f`:: Do not daemonize server
|
||||
|
||||
`PATH`:: The path to listen on
|
||||
|
||||
This service is usually started and managed using systemd toolset. The
|
||||
service is called 'qmeventd'.
|
||||
|
||||
systemctl start qmeventd
|
||||
|
||||
systemctl stop qmeventd
|
||||
|
||||
systemctl status qmeventd
|
||||
32
src/qmeventd/qmeventd.adoc
Normal file
32
src/qmeventd/qmeventd.adoc
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
ifdef::manvolnum[]
|
||||
qmeventd(8)
|
||||
===========
|
||||
:pve-toplevel:
|
||||
|
||||
NAME
|
||||
----
|
||||
|
||||
qmeventd - PVE QEMU Eventd Daemon
|
||||
|
||||
SYNOPSIS
|
||||
--------
|
||||
|
||||
include::qmeventd.8-synopsis.adoc[]
|
||||
|
||||
DESCRIPTION
|
||||
-----------
|
||||
endif::manvolnum[]
|
||||
|
||||
ifndef::manvolnum[]
|
||||
PVE QEMU Event Daemon
|
||||
=====================
|
||||
endif::manvolnum[]
|
||||
|
||||
`qmeventd` is a daemon that listens on PATH for incoming connections from
|
||||
a qemu qmp socket, and waits for SHUTDOWN events. When a client then
|
||||
disconnects, it executes `/usr/sbin/qm cleanup`. This makes it easy
|
||||
to clean up leftover tap devices, vgpus, etc.
|
||||
|
||||
ifdef::manvolnum[]
|
||||
include::pve-copyright.adoc[]
|
||||
endif::manvolnum[]
|
||||
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#define DEFAULT_KILL_TIMEOUT 60
|
||||
|
||||
static int verbose = 0;
|
||||
static int verbose = 1;
|
||||
static int kill_timeout = DEFAULT_KILL_TIMEOUT;
|
||||
static int epoll_fd = 0;
|
||||
static const char *progname;
|
||||
|
|
@ -209,6 +209,25 @@ void handle_qmp_event(struct Client *client, struct json_object *obj) {
|
|||
|
||||
// check if a backup is running and kill QEMU process if not
|
||||
terminate_check(client);
|
||||
} else if (!strcmp(json_object_get_string(event), "BLOCK_WRITE_THRESHOLD")) {
|
||||
struct json_object *data;
|
||||
struct json_object *nodename;
|
||||
if (json_object_object_get_ex(obj, "data", &data) &&
|
||||
json_object_object_get_ex(data, "node-name", &nodename)) {
|
||||
|
||||
// needs concurrency control
|
||||
char extend_queue_path[] = "/etc/pve/extend-queue";
|
||||
FILE *p_extend_queue = fopen(extend_queue_path, "a");
|
||||
if (p_extend_queue == NULL) {
|
||||
VERBOSE_PRINT(
|
||||
"%s: Couldn't open extend queue file %s", client->qemu.vmid, extend_queue_path
|
||||
);
|
||||
} else {
|
||||
const char *nodename_string = json_object_get_string(nodename);
|
||||
fprintf(p_extend_queue, "%s: %s\n", client->qemu.vmid, nodename_string);
|
||||
}
|
||||
fclose(p_extend_queue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue