[pve-devel] [PATCH storage v4] fix #957 iscsi: improve iscsi_test_portal logic
Mira Limbeck
m.limbeck at proxmox.com
Thu Mar 20 11:15:39 CET 2025
On 3/18/25 17:11, Friedrich Weber wrote:
> Hi, thanks for the new version! I think this is shaping up nicely. Some
> comments inline below, but only minor ones. So it may make sense to wait
> a couple of days for additional comments from others before sending a
> new version. I'll also run a few more tests this week and report back.
>
>> don't check tcp connection directly if there are already
>> sessions.
>>
>> pvestatd is calling check_connection every 10 seconds.
>> This check produces a lot of noise at the iscsi server logging.
>>
>> Signed-off-by: Victor Seva <linuxmaniac at torreviejawireless.org>
>> ---
>>
>> changes since v3:
>>
>> * iscsi_test_session():
>> read /sys/class/iscsi_session/session${sid}/state instead of
>> $ISCSIADM call
>>
>> * iscsi_test_portal():
>> add optional parameters target and cache. If target is defined,
>> used it to check session status instead of check tcp port
>>
>> * iscsi_discovery():
>> add optional parameters target and cache and pass it to
>> iscsi_test_portal call
>>
>> * iscsi_login():
>> add optional parameter cache and pass it to iscsi_discovery call
>>
>> * activate_storage():
>> pass cache parameter to iscsi_login call
>>
>> * check_connection():
>> add target and cache parameters to iscsi_test_portal call
>
> Thank you for adding these!
>
>>
>> src/PVE/Storage.pm | 2 +-
>> src/PVE/Storage/ISCSIPlugin.pm | 41 ++++++++++++++++++++++++++--------
>> 2 files changed, 33 insertions(+), 10 deletions(-)
>>
>> diff --git a/src/PVE/Storage.pm b/src/PVE/Storage.pm
>> index 3b4f041..c5d4ff8 100755
>> --- a/src/PVE/Storage.pm
>> +++ b/src/PVE/Storage.pm
>> @@ -1479,7 +1479,7 @@ sub scan_iscsi {
>> die "unable to parse/resolve portal address '${portal_in}'\n";
>> }
>>
>> - return PVE::Storage::ISCSIPlugin::iscsi_discovery([ $portal ]);
>> + return PVE::Storage::ISCSIPlugin::iscsi_discovery(undef, [ $portal ]);
>> }
>
> On first sight I wanted to suggest to keep $portals as the first
> argument and add $target and $cache as optional second+third argument,
> but now I see that `$target, $portals, $cache` allows us to have similar
> argument orderings for `iscsi_discovery`, `iscsi_login` and
> `iscsi_test_portal`, so I think this is fine.
>
>>
>> sub storage_default_format {
>> diff --git a/src/PVE/Storage/ISCSIPlugin.pm b/src/PVE/Storage/ISCSIPlugin.pm<
>> index eb70453..c7bacea 100644
>> --- a/src/PVE/Storage/ISCSIPlugin.pm
>> +++ b/src/PVE/Storage/ISCSIPlugin.pm
>> @@ -58,9 +58,32 @@ sub iscsi_session_list {
>> return $res;
>> }
>>
>> -sub iscsi_test_portal {
>> - my ($portal) = @_;
>> +sub iscsi_test_session {
>> + my ($sid) = @_;
>>
>> + if ($sid !~ m/^\d+$/) {
>
> It's safer to change \d to [0-9], see [1].
We parse it with `(\S+)` in iscsi_session_list(). But since it looks
like it can only be ASCII [0][1], limiting it to `[0-9]` should be better.
>
>> + die "session_id: '$sid' is not a number\n";
>> + }
>> + my $state = file_read_firstline("/sys/class/iscsi_session/session${sid}/state");
>> + if ($state eq 'LOGGED_IN') {
>> + return 1;
>> + }
>> + return 0;
>> +}
>
> Can be shortened to
>
> return $state eq 'LOGGED_IN';
>
> but it would be better to also check for definedness because
> file_read_firstline returns undef if the file does not exist, which is
> unlikely but not impossible:
>
> return defined($state) && $state eq 'LOGGED_IN';
>
>> +
>> +sub iscsi_test_portal {
>> + my ($target, $portal, $cache) = @_;
>> + $cache //= {};
>> +
>> + if (defined($target)) {
>
> Right, good catch, the $target == undef case is needed to allow initial
> discovery.
>
>> + # check session state instead if available
>> + my $sessions = iscsi_session($cache, $target);
>> + for my $session ($sessions->@*) {
>> + next if $session->{portal} ne $portal;
>> + return iscsi_test_session($session->{session_id});
>
> So if we have a session but it is not LOGGED_IN, we return 0.
> I know this is what I suggested in my v3 comment, but now I'm not so
> sure anymore. Couldn't it be the case that the session is broken for
> some reason, but discovery would still works? In such a case, we would
> now consider the portal offline. We could instead fall back to a TCP ping:
>
> my $state = iscsi_test_session($session->{session_id});
> return $state if $state;
>
> Any opinions (from others)?
After talking off-list about this, we do want to fall back to the
tcp_ping if the session is not logged in. For discovery no session is
needed. So even without a login, it might still be reachable via ping
and a discovery possible.
>> + }
>> + }
>> + # check portal via tcp
>> my ($server, $port) = PVE::Tools::parse_host_and_port($portal);
>> return 0 if !$server;
>> return PVE::Network::tcp_ping($server, $port || 3260, 2);
>> @@ -97,13 +120,13 @@ sub iscsi_portals {
>> }
>>
>> sub iscsi_discovery {
>> - my ($portals) = @_;
>> + my ($target, $portals, $cache) = @_;
>
> There is already a $target inside the deeply-nested `if`. To avoid
> confusion, it would be better to avoid variable shadowing. Probably the
> top-level one could be renamed to $discovery_target or $target_in or
> similar.
>
>>
>> assert_iscsi_support();
>>
>> my $res = {};
>> for my $portal ($portals->@*) {
>> - next if !iscsi_test_portal($portal); # fixme: raise exception here?
>> + next if !iscsi_test_portal($target, $portal, $cache); # fixme: raise exception here?
>>
>> my $cmd = [$ISCSIADM, '--mode', 'discovery', '--type', 'sendtargets', '--portal', $portal];
>> eval {
>> @@ -127,11 +150,11 @@ sub iscsi_discovery {
>> }
>>
>> sub iscsi_login {
>> - my ($target, $portals) = @_;
>> + my ($target, $portals, $cache) = @_;
>>
>> assert_iscsi_support();
>>
>> - eval { iscsi_discovery($portals); };
>> + eval { iscsi_discovery($target, $portals, $cache); };
>> warn $@ if $@;
>>
>> # Disable retries to avoid blocking pvestatd for too long, next iteration will retry anyway
>> @@ -445,7 +468,7 @@ sub activate_storage {
>> }
>>
>> if ($do_login) {
>> - eval { iscsi_login($scfg->{target}, $portals); };
>> + eval { iscsi_login($scfg->{target}, $portals, $cache); };
>> warn $@ if $@;
>> } else {
>> # make sure we get all devices
>> @@ -559,11 +582,11 @@ sub activate_volume {
>>
>> sub check_connection {
>> my ($class, $storeid, $scfg) = @_;
>> -
>> + my $cache = {};
>> my $portals = iscsi_portals($scfg->{target}, $scfg->{portal});
>>
>> for my $portal (@$portals) {
>> - my $result = iscsi_test_portal($portal);
>> + my $result = iscsi_test_portal($scfg->{target}, $portal, $cache);
>> return $result if $result;
>> }
>>
>> --
>> 2.43.0
>>
>>
>
>
> [1] https://pve.proxmox.com/wiki/Perl_Style_Guide#Matching_Digits_Fallacy
>
>
>
> _______________________________________________
> pve-devel mailing list
> pve-devel at lists.proxmox.com
> https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
>
>
I think with Friedrich's suggested changes it should to be good to merge.
[0] https://linux.die.net/man/8/iscsiadm
[1] https://www.kernel.org/doc/Documentation/filesystems/sysfs.txt
More information about the pve-devel
mailing list