diff mbox series

[11/11] iscsi: force destroy sesions when a network namespace exits

Message ID 20230506232930.195451-12-cleech@redhat.com (mailing list archive)
State Changes Requested
Headers show
Series Make iscsid-kernel communications namespace-aware | expand

Commit Message

Chris Leech May 6, 2023, 11:29 p.m. UTC
The namespace is gone, so there is no userspace to clean up.
Force close all the sessions.

This should be enough for software transports, there's no implementation
of migrating physical iSCSI hosts between network namespaces currently.

Reviewed-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Chris Leech <cleech@redhat.com>
---
 drivers/scsi/scsi_transport_iscsi.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

Comments

Mike Christie May 10, 2023, 8:09 p.m. UTC | #1
On 5/6/23 4:29 PM, Chris Leech wrote:
> The namespace is gone, so there is no userspace to clean up.
> Force close all the sessions.
> 
> This should be enough for software transports, there's no implementation
> of migrating physical iSCSI hosts between network namespaces currently.
> 
> Reviewed-by: Hannes Reinecke <hare@suse.de>
> Signed-off-by: Chris Leech <cleech@redhat.com>
> ---
>  drivers/scsi/scsi_transport_iscsi.c | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
> 
> diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
> index 15d28186996d..10e9414844d8 100644
> --- a/drivers/scsi/scsi_transport_iscsi.c
> +++ b/drivers/scsi/scsi_transport_iscsi.c
> @@ -5235,9 +5235,25 @@ static int __net_init iscsi_net_init(struct net *net)
>  
>  static void __net_exit iscsi_net_exit(struct net *net)
>  {
> +	struct iscsi_cls_session *session, *tmp;
>  	struct iscsi_net *isn;
> +	unsigned long flags;
> +	LIST_HEAD(sessions);
>  
>  	isn = net_generic(net, iscsi_net_id);
> +
> +	spin_lock_irqsave(&isn->sesslock, flags);
> +	list_replace_init(&isn->sesslist, &sessions);
> +	spin_unlock_irqrestore(&isn->sesslock, flags);
> +
> +	/* force session destruction, there is no userspace anymore */
> +	list_for_each_entry_safe(session, tmp, &sessions, sess_list) {
> +		device_for_each_child(&session->dev, NULL,
> +				      iscsi_iter_force_destroy_conn_fn);
> +		flush_work(&session->destroy_work);

I think if this flush_work actually flushed, then we would be doing a use
after free because the running work would free the session from under us.

We should never have a running destroy_work and be ale to see it on the sesslist
right? Maybe a WARN_ON or something else so it doesn't look like a possible
bug.


> +		__iscsi_destroy_session(&session->destroy_work);
> +	}
> +
>  	netlink_kernel_release(isn->nls);
>  	isn->nls = NULL;
>  }
Mike Christie May 10, 2023, 8:14 p.m. UTC | #2
On 5/10/23 1:09 PM, michael.christie@oracle.com wrote:
> On 5/6/23 4:29 PM, Chris Leech wrote:
>> The namespace is gone, so there is no userspace to clean up.
>> Force close all the sessions.
>>
>> This should be enough for software transports, there's no implementation
>> of migrating physical iSCSI hosts between network namespaces currently.
>>
>> Reviewed-by: Hannes Reinecke <hare@suse.de>
>> Signed-off-by: Chris Leech <cleech@redhat.com>
>> ---
>>  drivers/scsi/scsi_transport_iscsi.c | 16 ++++++++++++++++
>>  1 file changed, 16 insertions(+)
>>
>> diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
>> index 15d28186996d..10e9414844d8 100644
>> --- a/drivers/scsi/scsi_transport_iscsi.c
>> +++ b/drivers/scsi/scsi_transport_iscsi.c
>> @@ -5235,9 +5235,25 @@ static int __net_init iscsi_net_init(struct net *net)
>>  
>>  static void __net_exit iscsi_net_exit(struct net *net)
>>  {
>> +	struct iscsi_cls_session *session, *tmp;
>>  	struct iscsi_net *isn;
>> +	unsigned long flags;
>> +	LIST_HEAD(sessions);
>>  
>>  	isn = net_generic(net, iscsi_net_id);
>> +
>> +	spin_lock_irqsave(&isn->sesslock, flags);
>> +	list_replace_init(&isn->sesslist, &sessions);
>> +	spin_unlock_irqrestore(&isn->sesslock, flags);
>> +
>> +	/* force session destruction, there is no userspace anymore */
>> +	list_for_each_entry_safe(session, tmp, &sessions, sess_list) {
>> +		device_for_each_child(&session->dev, NULL,
>> +				      iscsi_iter_force_destroy_conn_fn);
>> +		flush_work(&session->destroy_work);
> 
> I think if this flush_work actually flushed, then we would be doing a use
> after free because the running work would free the session from under us.
> 
> We should never have a running destroy_work and be ale to see it on the sesslist
> right? Maybe a WARN_ON or something else so it doesn't look like a possible
> bug.

Maybe not a WARN_ON. What happens if there is running destroy_works for this
namespace and we return from this function?

> 
> 
>> +		__iscsi_destroy_session(&session->destroy_work);
>> +	}
>> +
>>  	netlink_kernel_release(isn->nls);
>>  	isn->nls = NULL;
>>  }
>
diff mbox series

Patch

diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
index 15d28186996d..10e9414844d8 100644
--- a/drivers/scsi/scsi_transport_iscsi.c
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -5235,9 +5235,25 @@  static int __net_init iscsi_net_init(struct net *net)
 
 static void __net_exit iscsi_net_exit(struct net *net)
 {
+	struct iscsi_cls_session *session, *tmp;
 	struct iscsi_net *isn;
+	unsigned long flags;
+	LIST_HEAD(sessions);
 
 	isn = net_generic(net, iscsi_net_id);
+
+	spin_lock_irqsave(&isn->sesslock, flags);
+	list_replace_init(&isn->sesslist, &sessions);
+	spin_unlock_irqrestore(&isn->sesslock, flags);
+
+	/* force session destruction, there is no userspace anymore */
+	list_for_each_entry_safe(session, tmp, &sessions, sess_list) {
+		device_for_each_child(&session->dev, NULL,
+				      iscsi_iter_force_destroy_conn_fn);
+		flush_work(&session->destroy_work);
+		__iscsi_destroy_session(&session->destroy_work);
+	}
+
 	netlink_kernel_release(isn->nls);
 	isn->nls = NULL;
 }