[pve-devel] [PATCH qemu-server] pending-delete: remember force-deletes

Wolfgang Bumiller w.bumiller at proxmox.com
Wed Aug 12 11:44:56 CEST 2015


The -force flag didn't have any effect since the pending
changes didn't carry over the the flag.
Now forced deletes have an exclamation mark prepended to the
option name.
---
 Note: Yes the patch became a bit "smaller" in that it reduced the resulting
 code size. (see numbers below)
 Old Patch =====> 96 insertions(+), 46 deletions(-)
 PVE/API2/Qemu.pm  | 53 +++-------------------------------------
 PVE/QemuServer.pm | 73 +++++++++++++++++++++++++++++++++++++++++++++++--------
 2 files changed, 67 insertions(+), 59 deletions(-)

diff --git a/PVE/API2/Qemu.pm b/PVE/API2/Qemu.pm
index 4dcbb26..a87ff4a 100644
--- a/PVE/API2/Qemu.pm
+++ b/PVE/API2/Qemu.pm
@@ -38,22 +38,6 @@ my $resolve_cdrom_alias = sub {
     }
 };
 
-my $test_deallocate_drive = sub {
-    my ($storecfg, $vmid, $key, $drive, $force) = @_;
-
-    if (!PVE::QemuServer::drive_is_cdrom($drive, 1)) {
-	my $volid = $drive->{file};
-	if ( PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
-	    if ($force || $key =~ m/^unused/) {
-		my $sid = PVE::Storage::parse_volume_id($volid);
-		return $sid;
-	    }
-	}
-    }
-
-    return undef;
-};
-
 my $check_storage_access = sub {
    my ($rpcenv, $authuser, $storecfg, $vmid, $settings, $default_storage) = @_;
 
@@ -213,34 +197,6 @@ my $create_disks = sub {
     return $vollist;
 };
 
-my $delete_drive = sub {
-    my ($conf, $storecfg, $vmid, $key, $drive, $force) = @_;
-
-    if (!PVE::QemuServer::drive_is_cdrom($drive)) {
-	my $volid = $drive->{file};
-
-	if (PVE::QemuServer::vm_is_volid_owner($storecfg, $vmid, $volid)) {
-	    if ($force || $key =~ m/^unused/) {
-		eval {
-		    # check if the disk is really unused
-		    my $used_paths = PVE::QemuServer::get_used_paths($vmid, $storecfg, $conf, 1, $key);
-		    my $path = PVE::Storage::path($storecfg, $volid);
-
-		    die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
-			if $used_paths->{$path};
-
-		    PVE::Storage::vdisk_free($storecfg, $volid);
-		};
-		die $@ if $@;
-	    } else {
-		PVE::QemuServer::add_unused_volume($conf, $volid, $vmid);
-	    }
-	}
-    }
-
-    delete $conf->{$key};
-};
-
 my $check_vm_modify_config_perm = sub {
     my ($rpcenv, $authuser, $vmid, $pool, $key_list) = @_;
 
@@ -955,19 +911,18 @@ my $update_vm_api  = sub {
 		if ($opt =~ m/^unused/) {
 		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
 		    my $drive = PVE::QemuServer::parse_drive($opt, $conf->{$opt});
-		    if (my $sid = &$test_deallocate_drive($storecfg, $vmid, $opt, $drive, $force)) {
-			$rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
-			&$delete_drive($conf, $storecfg, $vmid, $opt, $drive);
+		    if (PVE::QemuServer::try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser)) {
+			delete $conf->{$opt};
 			PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
 		    }
 		} elsif (PVE::QemuServer::valid_drivename($opt)) {
 		    $rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
 		    PVE::QemuServer::vmconfig_register_unused_drive($storecfg, $vmid, $conf, PVE::QemuServer::parse_drive($opt, $conf->{pending}->{$opt}))
 			if defined($conf->{pending}->{$opt});
-		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
+		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force);
 		    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
 		} else {
-		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt);
+		    PVE::QemuServer::vmconfig_delete_pending_option($conf, $opt, $force);
 		    PVE::QemuServer::update_config_nolock($vmid, $conf, 1);
 		}
 	    }
diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm
index da33b04..04aaf97 100644
--- a/PVE/QemuServer.pm
+++ b/PVE/QemuServer.pm
@@ -1518,14 +1518,17 @@ sub vm_is_volid_owner {
 }
 
 sub vmconfig_delete_pending_option {
-    my ($conf, $key) = @_;
+    my ($conf, $key, $force) = @_;
 
     delete $conf->{pending}->{$key};
-    my $pending_delete_hash = { $key => 1 };
+    my $pending_delete_hash = {};
     foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
-	$pending_delete_hash->{$opt} = 1;
+	$opt =~ s/^(!?)//;
+	$pending_delete_hash->{$opt} = $1;
     }
-    $conf->{pending}->{delete} = join(',', keys %$pending_delete_hash);
+    $pending_delete_hash->{$key} = $force ? '!' : '';
+    $conf->{pending}->{delete} = join(',',
+	map { $pending_delete_hash->{$_} . $_ } keys %$pending_delete_hash);
 }
 
 sub vmconfig_undelete_pending_option {
@@ -1533,13 +1536,15 @@ sub vmconfig_undelete_pending_option {
 
     my $pending_delete_hash = {};
     foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
-	$pending_delete_hash->{$opt} = 1;
+	$opt =~ s/^(!?)//;
+	$pending_delete_hash->{$opt} = $1;
     }
     delete $pending_delete_hash->{$key};
 
     my @keylist = keys %$pending_delete_hash;
     if (scalar(@keylist)) {
-	$conf->{pending}->{delete} = join(',', @keylist);
+	$conf->{pending}->{delete} = join(',',
+	    map { $pending_delete_hash->{$_} . $_ } @keylist);
     } else {
 	delete $conf->{pending}->{delete};
     }
@@ -1571,8 +1576,9 @@ sub vmconfig_cleanup_pending {
     # remove delete if option is not set
     my $pending_delete_hash = {};
     foreach my $opt (PVE::Tools::split_list($conf->{pending}->{delete})) {
+	$opt =~ s/^(!?)//;
 	if (defined($conf->{$opt})) {
-	    $pending_delete_hash->{$opt} = 1;
+	    $pending_delete_hash->{$opt} = $1;
 	} else {
 	    $changes = 1;
 	}
@@ -1580,7 +1586,8 @@ sub vmconfig_cleanup_pending {
 
     my @keylist = keys %$pending_delete_hash;
     if (scalar(@keylist)) {
-	$conf->{pending}->{delete} = join(',', @keylist);
+	$conf->{pending}->{delete} = join(',',
+	    map { $pending_delete_hash->{$_} . $_ } @keylist);
     } else {
 	delete $conf->{pending}->{delete};
     }
@@ -3995,6 +4002,7 @@ sub vmconfig_hotplug_pending {
 
     my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
     foreach my $opt (@delete) {
+	my $force = ($opt =~ s/^!//);
 	next if $selection && !$selection->{$opt};
 	eval {
 	    if ($opt eq 'hotplug') {
@@ -4020,7 +4028,7 @@ sub vmconfig_hotplug_pending {
 	    } elsif (valid_drivename($opt)) {
 		die "skip\n" if !$hotplug_features->{disk} || $opt =~ m/(ide|sata)(\d+)/;
 		vm_deviceunplug($vmid, $conf, $opt);
-		vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}));
+		vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
 	    } elsif ($opt =~ m/^memory$/) {
 		die "skip\n" if !$hotplug_features->{memory};
 		qemu_memory_hotplug($vmid, $conf, $defaults, $opt);
@@ -4102,6 +4110,50 @@ sub vmconfig_hotplug_pending {
     }
 }
 
+sub delete_drive {
+    my ($vmid, $storecfg, $conf, $key, $volid) = @_;
+
+    # check if the disk is really unused
+    my $used_paths = PVE::QemuServer::get_used_paths($vmid, $storecfg, $conf, 1, $key);
+    my $path = PVE::Storage::path($storecfg, $volid);
+
+    die "unable to delete '$volid' - volume is still in use (snapshot?)\n"
+	   if $used_paths->{$path};
+    PVE::Storage::vdisk_free($storecfg, $volid);
+}
+
+sub try_deallocate_drive {
+    my ($storecfg, $vmid, $conf, $key, $drive, $rpcenv, $authuser, $force) = @_;
+
+    if (($force || $key =~ /^unused/) && !drive_is_cdrom($drive, 1)) {
+	my $volid = $drive->{file};
+	if (vm_is_volid_owner($storecfg, $vmid, $volid)) {
+	    my $sid = PVE::Storage::parse_volume_id($volid);
+	    $rpcenv->check($authuser, "/storage/$sid", ['Datastore.AllocateSpace']);
+	    delete_drive($vmid, $storecfg, $conf, $key, $drive->{file});
+	    return 1;
+	}
+    }
+
+    return undef;
+}
+
+sub vmconfig_delete_or_detach_drive {
+    my ($vmid, $storecfg, $conf, $opt, $force) = @_;
+
+    my $drive = parse_drive($opt, $conf->{$opt});
+
+    my $rpcenv = PVE::RPCEnvironment::get();
+    my $authuser = $rpcenv->get_user();
+
+    if ($force) {
+	$rpcenv->check_vm_perm($authuser, $vmid, undef, ['VM.Config.Disk']);
+	try_deallocate_drive($storecfg, $vmid, $conf, $opt, $drive, $rpcenv, $authuser, $force);
+    } else {
+	vmconfig_register_unused_drive($storecfg, $vmid, $conf, $drive);
+    }
+}
+
 sub vmconfig_apply_pending {
     my ($vmid, $conf, $storecfg) = @_;
 
@@ -4109,13 +4161,14 @@ sub vmconfig_apply_pending {
 
     my @delete = PVE::Tools::split_list($conf->{pending}->{delete});
     foreach my $opt (@delete) { # delete
+	my $force = ($opt =~ s/^!//);
 	die "internal error" if $opt =~ m/^unused/;
 	$conf = load_config($vmid); # update/reload
 	if (!defined($conf->{$opt})) {
 	    vmconfig_undelete_pending_option($conf, $opt);
 	    update_config_nolock($vmid, $conf, 1);
 	} elsif (valid_drivename($opt)) {
-	    vmconfig_register_unused_drive($storecfg, $vmid, $conf, parse_drive($opt, $conf->{$opt}));
+	    vmconfig_delete_or_detach_drive($vmid, $storecfg, $conf, $opt, $force);
 	    vmconfig_undelete_pending_option($conf, $opt);
 	    delete $conf->{$opt};
 	    update_config_nolock($vmid, $conf, 1);
-- 
2.1.4





More information about the pve-devel mailing list