]> git.proxmox.com Git - pve-storage.git/blobdiff - PVE/Storage/LunCmd/LIO.pm
LIO: untaint values read from remote config
[pve-storage.git] / PVE / Storage / LunCmd / LIO.pm
index 9686582be236405534a4cd0a4c0b2c4b885e8ac4..f9e7143d1c30dde88fa9c02e8315e4288078be96 100644 (file)
@@ -121,6 +121,15 @@ my $get_config = sub {
     return $config;
 };
 
+# Return settings of a specific target
+my $get_target_settings = sub {
+   my ($scfg) = @_;
+
+   my $id = "$scfg->{portal}.$scfg->{target}";
+   return undef if !$SETTINGS;
+   return $SETTINGS->{$id};
+};
+
 # fetches and parses targetcli config from the portal
 my $parser = sub {
     my ($scfg) = @_;
@@ -139,16 +148,30 @@ my $parser = sub {
     my $jsonconfig = JSON->new->utf8->decode($config);
 
     my $haveTarget = 0;
-    foreach my $oneTarget (@{$jsonconfig->{targets}}) {
+    foreach my $target (@{$jsonconfig->{targets}}) {
        # only interested in iSCSI targets
-        if ($oneTarget->{fabric} eq 'iscsi' && $oneTarget->{wwn} eq $scfg->{target}) {
-           # find correct TPG
-           foreach my $oneTpg (@{$oneTarget->{tpgs}}) {
-                if ($oneTpg->{tag} == $tpg_tag) {
-                    $SETTINGS->{target} = $oneTpg;
-                    $haveTarget = 1;
-                    last;
+       next if !($target->{fabric} eq 'iscsi' && $target->{wwn} eq $scfg->{target});
+       # find correct TPG
+       foreach my $tpg (@{$target->{tpgs}}) {
+           if ($tpg->{tag} == $tpg_tag) {
+               my $res = [];
+               foreach my $lun (@{$tpg->{luns}}) {
+                   my ($idx, $storage_object);
+                   if ($lun->{index} =~ /^(\d+)$/) {
+                       $idx = $1;
+                   }
+                   if ($lun->{storage_object} =~ m|^($BACKSTORE/.*)$|) {
+                       $storage_object = $1;
+                   }
+                   die "Invalid lun definition in config!\n"
+                       if !(defined($idx) && defined($storage_object));
+                   push @$res, { index => $idx, storage_object => $storage_object };
                }
+
+               my $id = "$scfg->{portal}.$scfg->{target}";
+               $SETTINGS->{$id}->{luns} = $res;
+               $haveTarget = 1;
+               last;
            }
        }
     }
@@ -159,18 +182,27 @@ my $parser = sub {
     }
 };
 
+# Get prefix for backstores
+my $get_backstore_prefix = sub {
+    my ($scfg) = @_;
+    my $pool = $scfg->{pool};
+    $pool =~ s/\//-/g;
+    return $pool . '-';
+};
+
 # removes the given lu_name from the local list of luns
 my $free_lu_name = sub {
-    my ($lu_name) = @_;
-    my $new;
+    my ($scfg, $lu_name) = @_;
 
-    foreach my $lun (@{$SETTINGS->{target}->{luns}}) {
+    my $new = [];
+    my $target = $get_target_settings->($scfg);
+    foreach my $lun (@{$target->{luns}}) {
        if ($lun->{storage_object} ne "$BACKSTORE/$lu_name") {
            push @$new, $lun;
        }
     }
 
-    $SETTINGS->{target}->{luns} = $new;
+    $target->{luns} = $new;
 };
 
 # locally registers a new lun
@@ -182,7 +214,8 @@ my $register_lun = sub {
        storage_object => "$BACKSTORE/$volname",
        is_new => 1,
     };
-    push @{$SETTINGS->{target}->{luns}}, $conf;
+    my $target = $get_target_settings->($scfg);
+    push @{$target->{luns}}, $conf;
 
     return $conf;
 };
@@ -195,6 +228,16 @@ my $extract_volname = sub {
     my $base = get_base;
     if ($lunpath =~ /^$base\/$scfg->{pool}\/([\w\-]+)$/) {
        $volname = $1;
+       my $prefix = $get_backstore_prefix->($scfg);
+       my $target = $get_target_settings->($scfg);
+       foreach my $lun (@{$target->{luns}}) {
+           # If we have a lun with the pool prefix matching this vol, then return this one
+           # like pool-pve-vm-100-disk-0
+           # Else, just fallback to the old name scheme which is vm-100-disk-0
+           if ($lun->{storage_object} =~ /^$BACKSTORE\/($prefix$volname)$/) {
+               return $1;
+           }
+       }
     }
 
     return $volname;
@@ -206,9 +249,12 @@ my $list_view = sub {
     my $lun = undef;
 
     my $object = $params[0];
-    my $volname = $extract_volname->($scfg, $params[0]);
+    my $volname = $extract_volname->($scfg, $object);
+    my $target = $get_target_settings->($scfg);
 
-    foreach my $lun (@{$SETTINGS->{target}->{luns}}) {
+    return undef if !defined($volname); # nothing to search for..
+
+    foreach my $lun (@{$target->{luns}}) {
        if ($lun->{storage_object} eq "$BACKSTORE/$volname") {
            return $lun->{index};
        }
@@ -223,9 +269,10 @@ my $list_lun = sub {
     my $name = undef;
 
     my $object = $params[0];
-    my $volname = $extract_volname->($scfg, $params[0]);
+    my $volname = $extract_volname->($scfg, $object);
+    my $target = $get_target_settings->($scfg);
 
-    foreach my $lun (@{$SETTINGS->{target}->{luns}}) {
+    foreach my $lun (@{$target->{luns}}) {
        if ($lun->{storage_object} eq "$BACKSTORE/$volname") {
            return $object;
        }
@@ -244,6 +291,9 @@ my $create_lun = sub {
 
     my $device = $params[0];
     my $volname = $extract_volname->($scfg, $device);
+    # Here we create a new device, so we didn't get the volname prefixed with the pool name
+    # as extract_volname couldn't find a matching vol yet
+    $volname = $get_backstore_prefix->($scfg) . $volname;
     my $tpg = $scfg->{lio_tpg} || die "Target Portal Group not set, aborting!\n";
 
     # step 1: create backstore for device
@@ -251,7 +301,12 @@ my $create_lun = sub {
     my $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
     die $res->{msg} if !$res->{result};
 
-    # step 2: register lun with target
+    # step 2: enable unmap support on the backstore
+    @cliparams = ($BACKSTORE . '/' . $volname, 'set', 'attribute', 'emulate_tpu=1' );
+    $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
+    die $res->{msg} if !$res->{result};
+
+    # step 3: register lun with target
     # targetcli /iscsi/iqn.2018-04.at.bestsolution.somehost:target/tpg1/luns/ create /backstores/block/foobar
     @cliparams = ("/iscsi/$scfg->{target}/$tpg/luns/", 'create', "$BACKSTORE/$volname" );
     $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
@@ -283,32 +338,33 @@ my $delete_lun = sub {
     my $tpg = $scfg->{lio_tpg} || die "Target Portal Group not set, aborting!\n";
 
     my $path = $params[0];
-    my $volname = $extract_volname->($scfg, $params[0]);
-
-    foreach my $lun (@{$SETTINGS->{target}->{luns}}) {
-        if ($lun->{storage_object} eq "$BACKSTORE/$volname") {
-            # step 1: delete the lun
-            my @cliparams = ("/iscsi/$scfg->{target}/$tpg/luns/", 'delete', "lun$lun->{index}" );
-            my $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
-            do {
-                die $res->{msg};
-            } unless $res->{result};
-
-            # step 2: delete the backstore
-            @cliparams = ($BACKSTORE, 'delete', $volname);
-            $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
-            do {
-                die $res->{msg};
-            } unless $res->{result};
-
-            # step 3: save to be safe ...
-            $execute_remote_command->($scfg, $timeout, $targetcli, 'saveconfig');
-
-            # update interal cache
-            $free_lu_name->($volname);
-
-            last;
-        }
+    my $volname = $extract_volname->($scfg, $path);
+    my $target = $get_target_settings->($scfg);
+
+    foreach my $lun (@{$target->{luns}}) {
+       next if $lun->{storage_object} ne "$BACKSTORE/$volname";
+
+       # step 1: delete the lun
+       my @cliparams = ("/iscsi/$scfg->{target}/$tpg/luns/", 'delete', "lun$lun->{index}" );
+       my $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
+       do {
+           die $res->{msg};
+       } unless $res->{result};
+
+       # step 2: delete the backstore
+       @cliparams = ($BACKSTORE, 'delete', $volname);
+       $res = $execute_remote_command->($scfg, $timeout, $targetcli, @cliparams);
+       do {
+           die $res->{msg};
+       } unless $res->{result};
+
+       # step 3: save to be safe ...
+       $execute_remote_command->($scfg, $timeout, $targetcli, 'saveconfig');
+
+       # update interal cache
+       $free_lu_name->($scfg, $volname);
+
+       last;
     }
 
     return $res->{msg};
@@ -323,14 +379,8 @@ my $import_lun = sub {
 # needed for example when the underlying ZFS volume has been resized
 my $modify_lun = sub {
     my ($scfg, $timeout, $method, @params) = @_;
-    my $msg;
-
-    $msg = $delete_lun->($scfg, $timeout, $method, @params);
-    if ($msg) {
-       $msg = $create_lun->($scfg, $timeout, $method, @params);
-    }
-
-    return $msg;
+    # Nothing to do on volume modification for LIO
+    return undef;
 };
 
 my $add_view = sub {
@@ -352,10 +402,10 @@ my %lun_cmd_map = (
 sub run_lun_command {
     my ($scfg, $timeout, $method, @params) = @_;
 
-    # fetch configuration from target if we haven't yet
-    # or if our configuration is stale
+    # fetch configuration from target if we haven't yet or if it is stale
     my $timediff = time - $SETTINGS_TIMESTAMP;
-    if (!$SETTINGS || $timediff > $SETTINGS_MAXAGE) {
+    my $target = $get_target_settings->($scfg);
+    if (!$target || $timediff > $SETTINGS_MAXAGE) {
        $SETTINGS_TIMESTAMP = time;
        $parser->($scfg);
     }