On Tue, Jun 20, 2017 at 10:39:56PM +0200, m...@datanom.net wrote: > From: Michael Rasmussen <m...@datanom.net> > > Signed-off-by: Michael Rasmussen <m...@datanom.net> > --- > PVE/Storage/FreeNASPlugin.pm | 597 > ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 589 insertions(+), 8 deletions(-) > > diff --git a/PVE/Storage/FreeNASPlugin.pm b/PVE/Storage/FreeNASPlugin.pm > index e930cea..3a18a31 100644 > --- a/PVE/Storage/FreeNASPlugin.pm > +++ b/PVE/Storage/FreeNASPlugin.pm > @@ -17,11 +17,15 @@ use base qw(PVE::Storage::Plugin); > > my $api = '/api/v1.0'; > my $api_timeout = 20; # seconds > +my $max_luns = 20; # maximum supported luns per target group in freenas is 25 > + # but reserve 5 for temporary LUNs (snapshots with RAM and > + # snapshot backup) > my $rows_per_request = 50; # limit for get requests > # be aware. Setting limit very low (default > setting > # in FreeNAS API is 20) can cause race conditions > # on the FreeNAS host (seems like an unstable > # pagination algorithm implemented in FreeNAS) > +my $active_snaps = 4;
whitespace > my $version; > my $target_prefix = 'iqn.2005-10.org.freenas.ctl'; # automatically prepended > # in FreeNAS > @@ -245,6 +249,389 @@ my $freenas_list_zvol = sub { > return $list; > }; > whitespace > +my $freenas_no_more_extents = sub { isn't this misnamed? you are checking whether AN extent already exists for a specific target, not whether there are "(no) more extents"? > + my ($scfg, $target) = @_; > + whitespace > + my $extents = $freenas_request->($scfg, 'GET', > "services/iscsi/targettoextent/"); > + foreach my $extent (@$extents) { > + return 0 if $extent->{iscsi_target} == $target; > + } > + whitespace > + return 1; > +}; > + > +my $freenas_get_target = sub { > + my ($scfg, $vmid) = @_; > + my $target = undef; not needed, see below > + whitespace > + my $targets = $freenas_request->($scfg, 'GET', "services/iscsi/target/"); > + foreach my $t (@$targets) { > + if ($t->{iscsi_target_name} eq "vm-$vmid") { > + $target = $t->{id}; > + last; return $t->{id} if $t->{iscsi_target_name} eq "vm-$vmid"; > + } > + } > + whitespace > + return $target; return undef (although I think this is technically not needed) > +}; > + > +my $freenas_create_target = sub { > + my ($scfg, $vmid) = @_; > + my ($data, $target); > + whitespace > + $freenas_get_version->($scfg); > + > + if ($version < 110000) { > + $data = { > + iscsi_target_alias => "vm-$vmid", > + iscsi_target_name => "vm-$vmid", > + }; > + } elsif ($version < 110100) { > + $data = { > + iscsi_target_alias => "vm-$vmid", > + iscsi_target_name => "vm-$vmid", > + }; > + } else { > + die "FreeNAS-$version: Unsupported!\n"; > + } I don't get why you have this if here, but not in get_target.. > + > + eval { > + $target = $freenas_request->( > + $scfg, 'POST', "services/iscsi/target/", encode_json($data)); > + }; > + if ($@) { > + if ($@ =~ /^(\d+)\s*$/) { > + # Fetch existing target if code is 409 (conflict) > + die HTTP::Status::status_message($1) unless $1 == 409; > + return $freenas_get_target->($scfg, $vmid); > + } IMHO this is ugly: - unless - make freenas_request have a list of 'allowed' error status codes, and use the array variant here to get code and data. > + die "Creating target for 'vm-$vmid' failed: $@\n"; > + } > + whitespace > + return $target->{id}; > +}; > + > +my $freenas_delete_target = sub { > + my ($scfg, $target) = @_; > + > + $freenas_request->($scfg, 'DELETE', "services/iscsi/target/$target/"); > +}; > + > +my $freenas_get_target_name = sub { this does not make a freenas_request, so IMHO it should be named differently. also, it seems this is included in patches #3 and #4? > + my ($scfg, $volname) = @_; > + my $name = undef; > + whitespace > + if ($volname =~ /^(vm|base)-(\d+)-/) { > + $name = "vm-$2"; > + return "$target_prefix\:$name"; > + } > + > + return undef; > +}; > + > +my $freenas_get_target_group = sub { > + my ($scfg, $target) = @_; > + my $targetgroup = undef; > + whitespace > + my $targetgroups = $freenas_request->($scfg, 'GET', > "services/iscsi/targetgroup/"); > + > + foreach my $tgroup (@$targetgroups) { > + if ($tgroup->{iscsi_target} == $target && > + $tgroup->{iscsi_target_portalgroup} == $scfg->{portal_group} && > + $tgroup->{iscsi_target_initiatorgroup} == > $scfg->{initiator_group}) { > + $targetgroup = $tgroup->{id}; > + last; see above, drop the last, return from within the foreach, drop the useless $targetgroup > + } > + } > + whitespace > + return $targetgroup; > +}; > + > +my $freenas_create_target_group = sub { > + my ($scfg, $target) = @_; > + my $data; > + whitespace > + $freenas_get_version->($scfg); > + > + # Trying to create a target group which already exists will cause and > internal > + # server error so if creating an existing target group should be allowed > (return > + # existing target group number we must search prior to create > + my $tg = $freenas_get_target_group->($scfg, $target); > + return $tg if $tg; why do you have this here, but not for create_target, which has the same semantics? also, you overload $tg with two meanings: - get_target_group returns the ID - POST to services/iscsi/targetgroup returns the whole JSON response I wonder whether explicitly marking the subs and variables only containing IDs as such would prevent such confusions? > + whitespace > + if ($version < 110000) { > + $data = { > + iscsi_target => $target, > + iscsi_target_authgroup => $scfg->{auth_group} ? > $scfg->{auth_group} : undef, > + iscsi_target_portalgroup => $scfg->{portal_group}, > + iscsi_target_initiatorgroup => $scfg->{initiator_group}, > + iscsi_target_authtype => $scfg->{auth_type} ? $scfg->{auth_type} > : 'None', > + iscsi_target_initialdigest => "Auto", > + }; > + } elsif ($version < 110100) { > + $data = { > + iscsi_target => $target, > + iscsi_target_authgroup => $scfg->{auth_group} ? > $scfg->{auth_group} : undef, > + iscsi_target_portalgroup => $scfg->{portal_group}, > + iscsi_target_initiatorgroup => $scfg->{initiator_group}, > + iscsi_target_authtype => $scfg->{auth_type} ? $scfg->{auth_type} > : 'None', > + iscsi_target_initialdigest => "Auto", > + }; > + } else { > + die "FreeNAS-$version: Unsupported!\n"; > + } same comment like for the if in create_target > + > + eval { > + $tg = $freenas_request->( > + $scfg, 'POST', "services/iscsi/targetgroup/", > encode_json($data)); > + }; > + if ($@) { > + if ($@ =~ /^(\d+)\s*$/) { > + # Fetch existing target group if code is 409 (conflict) > + die HTTP::Status::status_message($1)."\n" unless $1 == 409; > + return $freenas_get_target_group->($scfg, $target); > + } and again, this is really convoluted - see create_target > + die "Creating target group for target '$target' failed: $@\n"; > + } > + whitespace > + return $tg->{id}; > +}; > + > +my $freenas_delete_target_group = sub { > + my ($scfg, $tg) = @_; > + > + $freenas_request->($scfg, 'DELETE', "services/iscsi/targetgroup/$tg"); > +}; > + > +my $freenas_create_extent = sub { > + my ($scfg, $zvol) = @_; > + my $data; > + whitespace > + $freenas_get_version->($scfg); > + whitespace > + if ($version < 110000) { > + $data = { > + iscsi_target_extent_type => 'Disk', > + iscsi_target_extent_name => $zvol, > + iscsi_target_extent_disk => "zvol/$scfg->{pool}/$zvol", > + }; > + } elsif ($version < 110100) { > + $data = { > + iscsi_target_extent_type => 'Disk', > + iscsi_target_extent_name => $zvol, > + iscsi_target_extent_disk => "zvol/$scfg->{pool}/$zvol", > + }; > + } else { > + die "FreeNAS-$version: Unsupported!\n"; > + } again - no such if in the associated GET sub? > + > + my $extent = $freenas_request->( > + $scfg, 'POST', "services/iscsi/extent/", encode_json($data)); > + whitespace > + return $extent->{id}; > +}; > + > +my $freenas_delete_extent = sub { > + my ($scfg, $extent) = @_; > + > + $freenas_request->($scfg, 'DELETE', "services/iscsi/extent/$extent/"); > +}; > + > +my $freenas_get_extent = sub { > + my ($scfg, $volname) = @_; > + my $extent = undef; > + whitespace > + my $extents = $freenas_request->($scfg, 'GET', "services/iscsi/extent/"); > + foreach my $ext (@$extents) { > + if ($ext->{iscsi_target_extent_path} =~ /$scfg->{pool}\/$volname$/) { > + $extent = $ext->{id}; > + last; > + } and the same comment again, drop the last, return here, ... > + } > + whitespace > + return $extent; > +}; > + > +my $freenas_create_target_to_exent = sub { > + my ($scfg, $target, $extent, $lunid) = @_; > + my $data; > + whitespace > + $freenas_get_version->($scfg); > + whitespace > + if ($version < 110000) { > + $data = { > + iscsi_target => $target, > + iscsi_extent => $extent, > + iscsi_lunid => $lunid, > + }; > + } elsif ($version < 110100) { > + $data = { > + iscsi_target => $target, > + iscsi_extent => $extent, > + iscsi_lunid => $lunid, > + }; > + } else { > + die "FreeNAS-$version: Unsupported!\n"; > + } and again, no such if in the GET sub? > + > + my $tg2extent = $freenas_request->( > + $scfg, 'POST', "services/iscsi/targettoextent/", encode_json($data)); does this not have the same semantics as create_target and create_target_group? > + whitespace > + return $tg2extent->{id}; > +}; > + > +my $freenas_delete_target_to_exent = sub { > + my ($scfg, $tg2exent) = @_; > + > + $freenas_request->($scfg, 'DELETE', > "services/iscsi/targettoextent/$tg2exent/"); > +}; > + > +my $freenas_get_target_to_exent = sub { > + my ($scfg, $extent, $target) = @_; > + my $t2extent = undef; > + whitespace > + my $t2extents = $freenas_request->($scfg, 'GET', > "services/iscsi/targettoextent/"); > + foreach my $t2ext (@$t2extents) { > + if ($t2ext->{iscsi_target} == $target && $t2ext->{iscsi_extent} == > $extent) { > + $t2extent = $t2ext->{id}; > + last; > + } again, drop the last, return here, ... > + } > + whitespace > + return $t2extent; > +}; > + > +my $freenas_find_free_diskname = sub { > + my ($storeid, $scfg, $vmid, $format) = @_; > + > + my $name = undef; > + my $volumes = $freenas_list_zvol->($scfg); > + > + my $disk_ids = {}; > + my $dat = $volumes->{$scfg->{pool}}; > + > + foreach my $image (keys %$dat) { > + my $volname = $dat->{$image}->{name}; > + if ($volname =~ m/vm-$vmid-disk-(\d+)/){ > + $disk_ids->{$1} = 1; > + } > + } > + > + for (my $i = 1; $i < $max_luns + 1; $i++) { > + if (!$disk_ids->{$i}) { > + return "vm-$vmid-disk-$i"; > + } > + } again, here you have the assumption that only numbers from 1 to $max_lun are valid - I would really like to decouple the LUN numbering from the disk index. > + whitespace > + die "Maximum number of LUNs($max_luns) for this VM $vmid in storage > '$storeid' is reached.\n"; > +}; > + > +my $freenas_get_lun_number = sub { > + my ($scfg, $volname) = @_; > + my $lunid = undef; > + whitespace > + if ($volname =~ /^(vm|base)-\d+-disk-(\d+)$/) { > + $lunid = $2 - 1; is there no other way? this seriously limits stuff that works with other storage plugins, like custom disk names.. > + } elsif ($volname =~ /^vm-(\d+)-state/) { > + # Find id for temporary LUN > + my $target = $freenas_get_target->($scfg, $1); > + my $id = $max_luns; > + my $t2extents = $freenas_request->($scfg, 'GET', > "services/iscsi/targettoextent/"); > + > + foreach my $t2extent (@$t2extents) { > + next unless $t2extent->{iscsi_target} == $target && > + $t2extent->{iscsi_lunid} + 1 > $max_luns && > + $t2extent->{iscsi_lunid} < $max_luns + $active_snaps; > + my $eid = $freenas_get_extent->($scfg, $volname); > + if ($eid) { > + my $extent = $freenas_request->($scfg, 'GET', > "services/iscsi/extent/$eid/"); > + # Request to get lunid for an existing lun > + last if $t2extent->{iscsi_extent} eq $eid; > + } > + $id++; > + } > + die "Max snapshots ($active_snaps) is reached\n" unless ($id - > $max_luns) < $active_snaps; > + $lunid = $id; > + } elsif ($volname =~ /^(vm|base)-\d+-disk-\d+\@vzdump$/) { > + # Required to be able to exposed read-only LUNs for snapshot backup > CT > + $lunid = $max_luns + $active_snaps; > + } > + whitespace > + return $lunid; > +}; > + > +my $freenas_create_lun = sub { > + my ($scfg, $vmid, $zvol) = @_; > + my ($target, $tg, $extent, $tg2exent) = (undef, undef, undef, undef); > + whitespace > + eval { > + $target = $freenas_create_target->($scfg, $vmid); > + die "create_lun-> Could not create target for VM '$vmid'\n" unless > $target; > + $tg = $freenas_create_target_group->($scfg, $target); > + die "create_lun-> Could not create target group for VM '$vmid'\n" > unless $tg; > + $extent = $freenas_create_extent->($scfg, $zvol); > + die "create_lun-> Could not create extent for VM '$vmid'\n" unless > $extent; > + my $lunid = $freenas_get_lun_number->($scfg, $zvol); > + die "create_lun-> $zvol: Bad name format for VM '$vmid'\n" unless > defined $lunid; > + $tg2exent = $freenas_create_target_to_exent->($scfg, $target, > $extent, $lunid); > + die "create_lun-> Could not create target to extent for VM > '$vmid'\n" unless defined $tg2exent; > + }; the feedback I gave on this is also not incorporated (yet?) > + if ($@) { > + my $err = $@; > + my $no_more_extents = 0; > + if ($tg2exent) { > + eval { > + $freenas_delete_target_to_exent->($scfg, $tg2exent); > + }; > + warn "Could not delete target to extent: $@\n" if $@; > + } > + if ($extent) { > + eval { > + $freenas_delete_extent->($scfg, $extent); > + }; > + warn "Could not delete extent: $@\n" if $@; > + } > + eval { > + $no_more_extents = $freenas_no_more_extents->($scfg, $target); > + }; > + warn "Could not decide whether more extents exists: $@\n" if $@; > + if ($target && $no_more_extents) { > + if ($tg) { > + eval { > + $freenas_delete_target_group->($scfg, $tg); > + }; > + warn "Could not delete target group: $@\n" if $@; > + } > + eval { > + $freenas_delete_target->($scfg, $target); > + }; > + warn "Could not delete target: $@\n" if $@; > + } > + die "create_lun: $err\n"; > + } > +}; > + > +my $freenas_create_zvol = sub { > + my ($scfg, $volname, $size) = @_; > + whitespace > + my $data = { > + name => $volname, > + volsize => $size, > + }; > + my $zvol = $freenas_request->( > + $scfg, 'POST', "storage/volume/$scfg->{pool}/zvols/", > encode_json($data)); > + > + die "$volname: Failed creating volume\n" unless $zvol && $zvol->{name}; > + whitespace > + return $zvol->{name}; > +}; > + > +my $freenas_delete_zvol = sub { > + my ($scfg, $volname) = @_; > + > + $freenas_request->($scfg, 'DELETE', > "storage/volume/$scfg->{pool}/zvols/$volname/"); > +}; > + > my $os_request = sub { > my ($cmd, $noerr, $timeout) = @_; > > @@ -263,16 +650,49 @@ my $os_request = sub { > return wantarray ? ($exit_code, $text) : $exit_code; > }; > > -my $freenas_get_target_name = sub { see way above - I guess this was a mishap when using 'git add -p'? > +my $disk_by_path = sub { > my ($scfg, $volname) = @_; > - my $name = undef; > - whitespace > - if ($volname =~ /^(vm|base)-(\d+)-/) { > - $name = "vm-$2"; > - return "$target_prefix\:$name"; > + > + my $target = $freenas_get_target_name->($scfg, $volname); > + my $lun = $freenas_get_lun_number->($scfg, $volname); > + my $path = > "/dev/disk/by-path/ip-$scfg->{portal}\:3260-iscsi-$target-lun-$lun"; > + > + return $path; > +}; > + > +my $build_lun_list = sub { > + my ($scfg, $sid, $lun) = @_; > + > + my $luns = {}; > + my $text = ''; > + my $exit = 0; > + > + eval { > + ($exit, $text) = $os_request->( > + ['iscsiadm', '-m', 'session', '-r', $sid, '-P3'], 1, 60); > + }; > + if ($@) { > + # An exist code of 22 means no active session otherwise an error > + if ($exit != 22) { > + die "$@\n"; > + } again, this is not how run_command with $noerr works. > + } > + if ($text =~ /.*Host Number:\s*(\d+)\s+State:\s+running(.*)/s) { > + my $host = $1; > + my $found = 0; > + for (split /^/, $2) { > + if ($_ =~ /Channel\s+(\d+)\s+Id\s+(\d+)\s+Lun:\s+(\d+)/) { > + if (defined $lun && $lun == $3) { > + $luns = {}; > + $found = 1; no need for $found and reseting $luns - simply return here? > + } > + $luns->{$3} = "$host:".int($1).":$2:$3"; > + last if $found; > + } > + } why not iterate line by line and match each line? would make the code easier to read. some comment about expected output would also be nice. > } > whitespace > - return undef; > + return $luns; > }; > whitespace > my $get_sid = sub { > @@ -360,6 +780,59 @@ my $remove_local_lun = sub { > } > }; > whitespace > +my $deactivate_luns = sub { > + # $luns contains a hash of luns to keep > + my ($scfg, $volname, $luns) = @_; > + > + $luns = {} unless $luns; unless > + my $sid; > + my $list = {}; > + > + $sid = $get_sid->($scfg, $volname); > + > + $list = $build_lun_list->($scfg, $sid); > + > + foreach my $key (keys %$list) { > + next if exists($luns->{$key}); s/exists/defined/ > + eval { > + $remove_local_lun->($list->{$key}); > + }; > + warn "Remove local LUN '$list->{$key}' failed: $@\n" if $@; $remove_local_lun already warns? > + } > +}; > + > +my $get_active_luns = sub { > + my ($class, $storeid, $scfg, $volname) = @_; > + > + my $sid = 0; in other places, you use -1 to denote an uninitialized sid? > + my $luns = {}; > + > + $sid = $get_sid->($scfg, $volname); > + > + if ($sid < 0) { > + # We have no active sessions so make one > + $sid = $create_session->($scfg, $volname); > + # Since no session existed prior to this call deactivate all LUN's > found > + $deactivate_luns->($scfg, $volname); the sub is called get_active_luns, but if there is no active session there are no active LUNs, so why create a session and deactivate all LUNs here? this seems like a strange side-effect that belongs somewhere else (or should be made explicit) > + } else { > + $luns = $build_lun_list->($scfg, $sid); > + } > + > + return $luns; > +}; > + > +my $rescan_session = sub { > + my ($class, $storeid, $scfg, $volname, $exclude_lun) = @_; > + > + my $luns_to_keep = $get_active_luns->($class, $storeid, $scfg, $volname); > + delete $luns_to_keep->{$exclude_lun} if defined $exclude_lun; > + my $sid = $get_sid->($scfg, $volname); > + die "Missing session\n" if $sid < 0; > + $os_request->(['iscsiadm', '-m', 'session', '-r', $sid, '-R'], 0, 60); > + $deactivate_luns->($scfg, $volname, $luns_to_keep); > + $delete_session->($scfg, $sid) unless %$luns_to_keep; unless > +}; > + > # Storage implementation > > sub volume_size_info { > @@ -453,6 +926,12 @@ sub path { > > my ($vtype, $vname, $vmid) = $class->parse_volname($volname); > whitespace > + $vname = "$vname\@$snapname" if $snapname; > + > + my $luns = $get_active_luns->($class, $storeid, $scfg, $vname); not used anywhere (or is this only because of the side-effect above!?)? > + my $path = $disk_by_path->($scfg, $vname); > + whitespace > + return ($path, $vmid, $vtype); > } > > sub create_base { > @@ -475,6 +954,28 @@ sub alloc_image { > my ($class, $storeid, $scfg, $vmid, $fmt, $name, $size) = @_; > die "unsupported format '$fmt'\n" if $fmt ne 'raw'; > > + die "illegal name '$name' - sould be 'vm-$vmid-*'\n" s/sould/should > + if $name && $name !~ m/^vm-$vmid-/; > + > + $name = $freenas_find_free_diskname->($storeid, $scfg, $vmid, $fmt) > unless $name; unless > + whitespace > + # Size is in KB but Freenas wants in bytes > + $size *= 1024; > + my $zvol = $freenas_create_zvol->($scfg, $name, $size); > + > + eval { > + $freenas_create_lun->($scfg, $vmid, $zvol); > + }; > + if ($@) { > + my $err = $@; > + eval { > + $freenas_delete_zvol->($scfg, $name); > + }; > + warn "Cleanup failed: $@\n" if $@; > + die "$err\n"; > + } > + > + return $name; > } > > sub free_image { > @@ -482,6 +983,47 @@ sub free_image { > > my ($vtype, $name, $vmid, $basename) = $class->parse_volname($volname); > > + my $target = $freenas_get_target->($scfg, $vmid); > + die "free_image-> missing target\n" unless $target; > + my $extent = $freenas_get_extent->($scfg, $name); > + die "free_image-> missing extent\n" unless $extent; > + my $tg2exent = $freenas_get_target_to_exent->($scfg, $extent, $target); > + die "free_image-> missing target to extent\n" unless $tg2exent; > + my $target_group = $freenas_get_target_group->($scfg, $target); > + die "free_image-> missing target group\n" unless $target_group; > + my $lun = $freenas_get_lun_number->($scfg, $name); > + die "free_image-> missing LUN\n" unless defined $lun; > + whitespace > + eval { > + my $res = $class->deactivate_volume($storeid, $scfg, $volname); > + warn "Could not deactivate volume '$volname'\n" unless $res; > + $freenas_delete_target_to_exent->($scfg, $tg2exent); > + $freenas_delete_extent->($scfg, $extent); > + if ($target && $freenas_no_more_extents->($scfg, $target)) { > + if ($target_group) { > + $freenas_delete_target_group->($scfg, $target_group); > + } > + $freenas_delete_target->($scfg, $target); > + } > + $freenas_delete_zvol->($scfg, $name); > + $class->volume_snapshot_delete($scfg, $storeid, $basename, > "__base__$vmid") if $basename; > + if ($isBase) { > + $basename = $name; > + $basename =~ s/^base-/vm-/; > + $class->volume_snapshot_delete($scfg, $storeid, $basename, > '__base__') if $basename; > + $freenas_delete_zvol->($scfg, $basename); > + } > + }; > + if ($@) { > + my $err = $@; > + eval { > + $freenas_create_lun->($scfg, $vmid, $name) unless $isBase; > + }; > + warn "Recreate LUN failed: $@\n" if $@; > + die "$err\n"; > + } > + > + return undef; > } > > sub volume_resize { > @@ -579,6 +1121,35 @@ sub deactivate_storage { > # deactivate all luns except our luns > sub activate_volume { > my ($class, $storeid, $scfg, $volname, $snapname, $cache) = @_; > + my $lun; > + whitespace > + my (undef, $name, $vmid) = $class->parse_volname($volname); > + whitespace > + my $luns_to_keep = $get_active_luns->($class, $storeid, $scfg, $name); > + > + if ($snapname) { > + eval { > + $freenas_create_lun->($scfg, $vmid, "$name\@$snapname"); > + $lun = $freenas_get_lun_number->($scfg, "$name\@$snapname"); > + $luns_to_keep->{$lun} = "0:0:0:$lun"; > + }; > + if ($@) { > + die "$@ - unable to activate snapshot from remote FreeNAS > storage\n"; > + } > + } > + whitespace > + $lun = $freenas_get_lun_number->($scfg, $name); > + $luns_to_keep->{$lun} = "0:0:0:$lun"; > + > + my $sid = $get_sid->($scfg, $name); > + die "activate_volume-> Missing session\n" if $sid < 0; > + # Add new LUN's to session > + $os_request->(['iscsiadm', '-m', 'session', '-r', $sid, '-R'], 0, 60); > + $os_request->( > + ['udevadm', 'trigger', '--type=devices', > '--subsystem-match=scsi_disk'], 0, 60); > + $os_request->(['udevadm', 'settle', '-t', $api_timeout], 0, 60); > + # Remove all LUN's from session which is not currently active > + $deactivate_luns->($scfg, $name, $luns_to_keep); > > return 1; > } > @@ -593,7 +1164,17 @@ sub deactivate_volume { > > my (undef, $name) = $class->parse_volname($volname); > > - return 1; > + my $luns_to_keep = $get_active_luns->($class, $storeid, $scfg, $name); > + > + my $lun = $freenas_get_lun_number->($scfg, $name); > + delete $luns_to_keep->{$lun}; > + > + my $sid = $get_sid->($scfg, $name); > + die "deactivate_volume-> Missing session\n" if $sid < 0; > + $deactivate_luns->($scfg, $name, $luns_to_keep); > + $delete_session->($scfg, $sid) unless %$luns_to_keep; > + > + return 1; > } > > 1; > -- > 2.11.0 > > > ---- > > This mail was virus scanned and spam checked before delivery. > This mail is also DKIM signed. See header dkim-signature. > > _______________________________________________ > pve-devel mailing list > pve-devel@pve.proxmox.com > https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel _______________________________________________ pve-devel mailing list pve-devel@pve.proxmox.com https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel