]> git.proxmox.com Git - qemu-server.git/blobdiff - PVE/QemuServer.pm
live-restore: fail early if target storage doesn't exist
[qemu-server.git] / PVE / QemuServer.pm
index 2f0b2e8ec952c99a2c4e40f18c5800629e9ba320..3126e14ea8f26e67f1c64417a3ae51647ee36862 100644 (file)
@@ -315,11 +315,13 @@ my $confdesc = {
     cpuunits => {
        optional => 1,
        type => 'integer',
-        description => "CPU weight for a VM.",
-       verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler. The larger the number is, the more CPU time this VM gets. Number is relative to weights of all the other running VMs.",
+        description => "CPU weight for a VM, will be clamped to [1, 10000] in cgroup v2.",
+       verbose_description => "CPU weight for a VM. Argument is used in the kernel fair scheduler."
+           ." The larger the number is, the more CPU time this VM gets. Number is relative to"
+           ." weights of all the other running VMs.",
        minimum => 2,
        maximum => 262144,
-       default => 1024,
+       default => 'cgroup v1: 1024, cgroup v2: 100',
     },
     memory => {
        optional => 1,
@@ -830,9 +832,22 @@ for (my $i = 0; $i < $MAX_NUMA; $i++)  {
     $confdesc->{"numa$i"} = $numadesc;
 }
 
-my $nic_model_list = ['rtl8139', 'ne2k_pci', 'e1000',  'pcnet',  'virtio',
-                     'ne2k_isa', 'i82551', 'i82557b', 'i82559er', 'vmxnet3',
-                     'e1000-82540em', 'e1000-82544gc', 'e1000-82545em'];
+my $nic_model_list = [
+    'e1000',
+    'e1000-82540em',
+    'e1000-82544gc',
+    'e1000-82545em',
+    'e1000e',
+    'i82551',
+    'i82557b',
+    'i82559er',
+    'ne2k_isa',
+    'ne2k_pci',
+    'pcnet',
+    'rtl8139',
+    'virtio',
+    'vmxnet3',
+];
 my $nic_model_list_txt = join(' ', sort @$nic_model_list);
 
 my $net_fmt_bridge_descr = <<__EOD__;
@@ -1530,14 +1545,15 @@ sub print_drive_commandline_full {
     my $format = $drive->{format};
     my $drive_id = get_drive_id($drive);
 
+    my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
+    my $scfg = $storeid ? PVE::Storage::storage_config($storecfg, $storeid) : undef;
+
     if (drive_is_cdrom($drive)) {
        $path = get_iso_path($storecfg, $vmid, $volid);
         die "$drive_id: cannot back cdrom drive with PBS snapshot\n" if $pbs_name;
     } else {
-       my ($storeid, $volname) = PVE::Storage::parse_volume_id($volid, 1);
        if ($storeid) {
            $path = PVE::Storage::path($storecfg, $volid);
-           my $scfg = PVE::Storage::storage_config($storecfg, $storeid);
            $format //= qemu_img_format($scfg, $volname);
        } else {
            $path = $volid;
@@ -1594,13 +1610,20 @@ sub print_drive_commandline_full {
 
     if (my $cache = $drive->{cache}) {
        $cache_direct = $cache =~ /^(?:off|none|directsync)$/;
-    } elsif (!drive_is_cdrom($drive)) {
+    } elsif (!drive_is_cdrom($drive) && !($scfg && $scfg->{type} eq 'btrfs' && !$scfg->{nocow})) {
        $opts .= ",cache=none";
        $cache_direct = 1;
     }
 
+    # io_uring with cache mode writeback or writethrough on krbd will hang...
+    my $rbd_no_io_uring = $scfg && $scfg->{type} eq 'rbd' && $scfg->{krbd} && !$cache_direct;
+
+    # io_uring with cache mode writeback or writethrough on LVM will hang, without cache only
+    # sometimes, just plain disable...
+    my $lvm_no_io_uring = $scfg && $scfg->{type} eq 'lvm';
+
     if (!$drive->{aio}) {
-       if ($io_uring) {
+       if ($io_uring && !$rbd_no_io_uring && !$lvm_no_io_uring) {
            # io_uring supports all cache modes
            $opts .= ",aio=io_uring";
        } else {
@@ -1698,6 +1721,8 @@ sub print_netdevice_full {
            $romfile = 'pxe-virtio.rom';
        } elsif ($device eq 'e1000') {
            $romfile = 'pxe-e1000.rom';
+       } elsif ($device eq 'e1000e') {
+           $romfile = 'pxe-e1000e.rom';
        } elsif ($device eq 'ne2k') {
            $romfile = 'pxe-ne2k_pci.rom';
        } elsif ($device eq 'pcnet') {
@@ -3166,6 +3191,10 @@ sub query_understood_cpu_flags {
     return \@flags;
 }
 
+my sub get_cpuunits {
+    my ($conf) = @_;
+    return $conf->{cpuunits} // (PVE::CGroup::cgroup_mode() == 2 ? 100 : 1024);
+}
 sub config_to_command {
     my ($storecfg, $vmid, $conf, $defaults, $forcemachine, $forcecpu,
         $pbs_backing) = @_;
@@ -3235,8 +3264,7 @@ sub config_to_command {
     my $use_old_bios_files = undef;
     ($use_old_bios_files, $machine_type) = qemu_use_old_bios_files($machine_type);
 
-    my $cpuunits = defined($conf->{cpuunits}) ?
-            $conf->{cpuunits} : $defaults->{cpuunits};
+    my $cpuunits = get_cpuunits($conf);
 
     push @$cmd, $kvm_binary;
 
@@ -3322,8 +3350,12 @@ sub config_to_command {
            $size_str = ",size=" . (-s $ovmf_vars);
        }
 
-       # on slower ceph clusters, booting without cache on efidisk can take a while, see #3329
-       my $cache = $path =~ m/^rbd:/ ? ',cache=writeback' : '';
+       # SPI flash does lots of read-modify-write OPs, without writeback this gets really slow #3329
+       my $cache = "";
+       if ($path =~ m/^rbd:/) {
+               $cache = ',cache=writeback';
+               $path .= ':rbd_cache_policy=writeback'; # avoid write-around, we *need* to cache writes too
+       }
 
        push @$cmd, '-drive', "if=pflash,unit=0,format=raw,readonly=on,file=$ovmf_code";
        push @$cmd, '-drive', "if=pflash,unit=1$cache,format=$format,id=drive-efidisk0$size_str,file=${path}${read_only_str}";
@@ -3782,6 +3814,11 @@ sub config_to_command {
        print "activating and using '$vmstate' as vmstate\n";
     }
 
+    if (PVE::QemuConfig->is_template($conf)) {
+       # needed to workaround base volumes being read-only
+       push @$cmd, '-snapshot';
+    }
+
     # add custom args
     if ($conf->{args}) {
        my $aa = PVE::Tools::split_args($conf->{args});
@@ -4608,7 +4645,7 @@ sub vmconfig_hotplug_pending {
                die "skip\n" if !$hotplug_features->{memory};
                PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
            } elsif ($opt eq 'cpuunits') {
-               $cgroup->change_cpu_shares(undef, $defaults->{cpuunits});
+               $cgroup->change_cpu_shares(undef, 1024);
            } elsif ($opt eq 'cpulimit') {
                $cgroup->change_cpu_quota(-1, 100000);
            } else {
@@ -4702,7 +4739,7 @@ sub vmconfig_hotplug_pending {
                die "skip\n" if !$hotplug_features->{memory};
                $value = PVE::QemuServer::Memory::qemu_memory_hotplug($vmid, $conf, $defaults, $opt, $value);
            } elsif ($opt eq 'cpuunits') {
-               $cgroup->change_cpu_shares($conf->{pending}->{$opt}, $defaults->{cpuunits});
+               $cgroup->change_cpu_shares($conf->{pending}->{$opt}, 1024);
            } elsif ($opt eq 'cpulimit') {
                my $cpulimit = $conf->{pending}->{$opt} == 0 ? -1 : int($conf->{pending}->{$opt} * 100000);
                $cgroup->change_cpu_quota($cpulimit, 100000);
@@ -5269,8 +5306,7 @@ sub vm_start_nolock {
     # timeout should be more than enough here...
     PVE::Systemd::wait_for_unit_removed("$vmid.scope", 5);
 
-    my $cpuunits = defined($conf->{cpuunits}) ? $conf->{cpuunits}
-                                             : $defaults->{cpuunits};
+    my $cpuunits = get_cpuunits($conf);
 
     my $start_timeout = $params->{timeout} // config_aware_timeout($conf, $resume);
     my %run_params = (
@@ -5294,6 +5330,7 @@ sub vm_start_nolock {
     );
 
     if (PVE::CGroup::cgroup_mode() == 2) {
+       $cpuunits = 10000 if $cpuunits >= 10000; # else we get an error
        $properties{CPUWeight} = $cpuunits;
     } else {
        $properties{CPUShares} = $cpuunits;
@@ -6356,35 +6393,36 @@ sub restore_proxmox_backup_archive {
        # allocate volumes
        my $map = $restore_allocate_devices->($storecfg, $virtdev_hash, $vmid);
 
-       if (!$options->{live}) {
-           foreach my $virtdev (sort keys %$virtdev_hash) {
-               my $d = $virtdev_hash->{$virtdev};
-               next if $d->{is_cloudinit}; # no need to restore cloudinit
-
-               my $volid = $d->{volid};
+       foreach my $virtdev (sort keys %$virtdev_hash) {
+           my $d = $virtdev_hash->{$virtdev};
+           next if $d->{is_cloudinit}; # no need to restore cloudinit
 
-               my $path = PVE::Storage::path($storecfg, $volid);
+           # this fails if storage is unavailable
+           my $volid = $d->{volid};
+           my $path = PVE::Storage::path($storecfg, $volid);
 
-               my $pbs_restore_cmd = [
-                   '/usr/bin/pbs-restore',
-                   '--repository', $repo,
-                   $pbs_backup_name,
-                   "$d->{devname}.img.fidx",
-                   $path,
-                   '--verbose',
-                   ];
+           # for live-restore we only want to preload the efidisk
+           next if $options->{live} && $virtdev ne 'efidisk0';
 
-               push @$pbs_restore_cmd, '--format', $d->{format} if $d->{format};
-               push @$pbs_restore_cmd, '--keyfile', $keyfile if -e $keyfile;
+           my $pbs_restore_cmd = [
+               '/usr/bin/pbs-restore',
+               '--repository', $repo,
+               $pbs_backup_name,
+               "$d->{devname}.img.fidx",
+               $path,
+               '--verbose',
+               ];
 
-               if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
-                   push @$pbs_restore_cmd, '--skip-zero';
-               }
+           push @$pbs_restore_cmd, '--format', $d->{format} if $d->{format};
+           push @$pbs_restore_cmd, '--keyfile', $keyfile if -e $keyfile;
 
-               my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
-               print "restore proxmox backup image: $dbg_cmdstring\n";
-               run_command($pbs_restore_cmd);
+           if (PVE::Storage::volume_has_feature($storecfg, 'sparseinit', $volid)) {
+               push @$pbs_restore_cmd, '--skip-zero';
            }
+
+           my $dbg_cmdstring = PVE::Tools::cmd2string($pbs_restore_cmd);
+           print "restore proxmox backup image: $dbg_cmdstring\n";
+           run_command($pbs_restore_cmd);
        }
 
        $fh->seek(0, 0) || die "seek failed - $!\n";
@@ -6439,6 +6477,7 @@ sub restore_proxmox_backup_archive {
        my $conf = PVE::QemuConfig->load_config($vmid);
        die "cannot do live-restore for template\n" if PVE::QemuConfig->is_template($conf);
 
+       delete $devinfo->{'drive-efidisk0'}; # this special drive is already restored before start
        pbs_live_restore($vmid, $conf, $storecfg, $devinfo, $repo, $keyfile, $pbs_backup_name);
 
        PVE::QemuConfig->remove_lock($vmid, "create");