All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough
@ 2018-09-17 21:35 Bart Van Assche
  2018-10-06 12:05 ` Christoph Hellwig
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Bart Van Assche @ 2018-09-17 21:35 UTC (permalink / raw)
  To: target-devel

A session must only be released after all code that accesses the session
structure has finished. Make sure that this is the case by introducing a
new command counter per session that is only decremented after the
.release_cmd() callback has finished.

Signed-off-by: Bart Van Assche <bvanassche@acm.org>
Cc: Nicholas Bellinger <nab@linux-iscsi.org>
Cc: Mike Christie <mchristi@redhat.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Hannes Reinecke <hare@suse.de>
---
 drivers/target/target_core_transport.c | 27 +++++++++++++++++---------
 include/target/target_core_base.h      |  1 +
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 94e9d03af99d..54ccd8f56a57 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -224,6 +224,13 @@ void transport_subsystem_check_init(void)
 	sub_api_initialized = 1;
 }
 
+static void target_release_sess_cmd_refcnt(struct percpu_ref *ref)
+{
+	struct se_session *sess = container_of(ref, typeof(*sess), cmd_count);
+
+	wake_up(&sess->cmd_list_wq);
+}
+
 /**
  * transport_init_session - initialize a session object
  * @se_sess: Session object pointer.
@@ -237,7 +244,8 @@ int transport_init_session(struct se_session *se_sess)
 	INIT_LIST_HEAD(&se_sess->sess_cmd_list);
 	spin_lock_init(&se_sess->sess_cmd_lock);
 	init_waitqueue_head(&se_sess->cmd_list_wq);
-	return 0;
+	return percpu_ref_init(&se_sess->cmd_count,
+			       target_release_sess_cmd_refcnt, 0, GFP_KERNEL);
 }
 EXPORT_SYMBOL(transport_init_session);
 
@@ -587,6 +595,7 @@ void transport_free_session(struct se_session *se_sess)
 		sbitmap_queue_free(&se_sess->sess_tag_pool);
 		kvfree(se_sess->sess_cmd_map);
 	}
+	percpu_ref_exit(&se_sess->cmd_count);
 	kmem_cache_free(se_sess_cache, se_sess);
 }
 EXPORT_SYMBOL(transport_free_session);
@@ -2730,6 +2739,7 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
 	}
 	se_cmd->transport_state |= CMD_T_PRE_EXECUTE;
 	list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
+	percpu_ref_get(&se_sess->cmd_count);
 out:
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
@@ -2760,8 +2770,6 @@ static void target_release_cmd_kref(struct kref *kref)
 	if (se_sess) {
 		spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 		list_del_init(&se_cmd->se_cmd_list);
-		if (list_empty(&se_sess->sess_cmd_list))
-			wake_up(&se_sess->cmd_list_wq);
 		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 	}
 
@@ -2769,6 +2777,8 @@ static void target_release_cmd_kref(struct kref *kref)
 	se_cmd->se_tfo->release_cmd(se_cmd);
 	if (compl)
 		complete(compl);
+
+	percpu_ref_put(&se_sess->cmd_count);
 }
 
 /**
@@ -2897,6 +2907,8 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
 	se_sess->sess_tearing_down = 1;
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
+
+	percpu_ref_kill_and_confirm(&se_sess->cmd_count, NULL);
 }
 EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
 
@@ -2911,17 +2923,14 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
 
 	WARN_ON_ONCE(!se_sess->sess_tearing_down);
 
-	spin_lock_irq(&se_sess->sess_cmd_lock);
 	do {
-		ret = wait_event_interruptible_lock_irq_timeout(
-				se_sess->cmd_list_wq,
-				list_empty(&se_sess->sess_cmd_list),
-				se_sess->sess_cmd_lock, 180 * HZ);
+		ret = wait_event_timeout(se_sess->cmd_list_wq,
+				percpu_ref_is_zero(&se_sess->cmd_count),
+				180 * HZ);
 		list_for_each_entry(cmd, &se_sess->sess_cmd_list, se_cmd_list)
 			target_show_cmd("session shutdown: still waiting for ",
 					cmd);
 	} while (ret <= 0);
-	spin_unlock_irq(&se_sess->sess_cmd_lock);
 }
 EXPORT_SYMBOL(target_wait_for_sess_cmds);
 
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 7a4ee7852ca4..2cfd3b4573b0 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -602,6 +602,7 @@ struct se_session {
 	struct se_node_acl	*se_node_acl;
 	struct se_portal_group *se_tpg;
 	void			*fabric_sess_ptr;
+	struct percpu_ref	cmd_count;
 	struct list_head	sess_list;
 	struct list_head	sess_acl_list;
 	struct list_head	sess_cmd_list;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough
  2018-09-17 21:35 [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough Bart Van Assche
@ 2018-10-06 12:05 ` Christoph Hellwig
  2018-10-07  3:28 ` Nicholas A. Bellinger
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Christoph Hellwig @ 2018-10-06 12:05 UTC (permalink / raw)
  To: target-devel

On Mon, Sep 17, 2018 at 02:35:42PM -0700, Bart Van Assche wrote:
> A session must only be released after all code that accesses the session
> structure has finished. Make sure that this is the case by introducing a
> new command counter per session that is only decremented after the
> .release_cmd() callback has finished.

Can you explain what problems we are running into right now due to the
lack of a refcount?

> @@ -2897,6 +2907,8 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
>  	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
>  	se_sess->sess_tearing_down = 1;
>  	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
> +
> +	percpu_ref_kill_and_confirm(&se_sess->cmd_count, NULL);

This is equivalent ot a plain percpu_ref_kill call.

> @@ -2911,17 +2923,14 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
>  
>  	WARN_ON_ONCE(!se_sess->sess_tearing_down);
>  
> -	spin_lock_irq(&se_sess->sess_cmd_lock);
>  	do {
> -		ret = wait_event_interruptible_lock_irq_timeout(
> -				se_sess->cmd_list_wq,
> -				list_empty(&se_sess->sess_cmd_list),
> -				se_sess->sess_cmd_lock, 180 * HZ);
> +		ret = wait_event_timeout(se_sess->cmd_list_wq,
> +				percpu_ref_is_zero(&se_sess->cmd_count),
> +				180 * HZ);

So this is basically the big change - check for a zero reference instead
of the list_empty.

I fail to see how this makes a difference, and also why we even need a
percpu ref as the get/pull calls are under, or right next to
sess_cmd_lock critical sections.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough
  2018-09-17 21:35 [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough Bart Van Assche
  2018-10-06 12:05 ` Christoph Hellwig
@ 2018-10-07  3:28 ` Nicholas A. Bellinger
  2018-10-08 16:14 ` Bart Van Assche
  2018-10-08 16:32 ` Bart Van Assche
  3 siblings, 0 replies; 5+ messages in thread
From: Nicholas A. Bellinger @ 2018-10-07  3:28 UTC (permalink / raw)
  To: target-devel

On Mon, 2018-09-17 at 14:35 -0700, Bart Van Assche wrote:
> A session must only be released after all code that accesses the session
> structure has finished. Make sure that this is the case by introducing a
> new command counter per session that is only decremented after the
> .release_cmd() callback has finished.
> 
> Signed-off-by: Bart Van Assche <bvanassche@acm.org>
> Cc: Nicholas Bellinger <nab@linux-iscsi.org>
> Cc: Mike Christie <mchristi@redhat.com>
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Hannes Reinecke <hare@suse.de>
> ---
>  drivers/target/target_core_transport.c | 27 +++++++++++++++++---------
>  include/target/target_core_base.h      |  1 +
>  2 files changed, 19 insertions(+), 9 deletions(-)
> 

Per HCH's earlier comment.  Is this required to fix a regression
introduced by commit 00d909a107 in mainline..?  Is it SRPT specific..?

Btw, I'm not completely against moving to a se_sess percpu_ref for
tracking se_cmd association to a session for the purposes of active I/O
shutdown.  However, inter-mixing it with existing se_sess->sess_cmd_lock
+ se_sess->sess_cmd_list for the single benefit of dropping
->sess_cmd_lock during non fast-path code in target_wait_for_sess_cmd()
doesn't really make sense.

That said, what would be better is utilize a new se_sess percpu_ref that
eliminates se_sess->sess_cmd_lock + se_sess->sess_cmd_list all-together!

How..?  Well, what about using the newly sbitmap converted (thanks
willy) se_sess->sess_tag_pool instead..?  Similar to how
blk_mq_queue_tag_busy_iter() uses sbitmap_for_each_set(), the same could
be done to eliminate se_sess->sess_cmd_list all together.

However, that would depend on all upstream fabric drivers using
se_sess->sess_tag_pool.  This is true in all but one case since 4.6.x,
the SRPT driver.

In addition, there would likely be some hairy TMR ABORT_TASK issues to
resolve no doubt, but killing se_sess->sess_cmd_[lock,list] and moving
to per se_session percpu_ref counting is a good goal.

Anyways, I'll review this patch as a starting point to remove
se_sess->sess_cmd_[lock,list] all-together.  Comments inline below.

> diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
> index 94e9d03af99d..54ccd8f56a57 100644
> --- a/drivers/target/target_core_transport.c
> +++ b/drivers/target/target_core_transport.c
> @@ -224,6 +224,13 @@ void transport_subsystem_check_init(void)
>  	sub_api_initialized = 1;
>  }
>  
> +static void target_release_sess_cmd_refcnt(struct percpu_ref *ref)
> +{
> +	struct se_session *sess = container_of(ref, typeof(*sess), cmd_count);
> +
> +	wake_up(&sess->cmd_list_wq);
> +}
> +
>  /**
>   * transport_init_session - initialize a session object
>   * @se_sess: Session object pointer.
> @@ -237,7 +244,8 @@ int transport_init_session(struct se_session *se_sess)
>  	INIT_LIST_HEAD(&se_sess->sess_cmd_list);
>  	spin_lock_init(&se_sess->sess_cmd_lock);
>  	init_waitqueue_head(&se_sess->cmd_list_wq);
> -	return 0;
> +	return percpu_ref_init(&se_sess->cmd_count,
> +			       target_release_sess_cmd_refcnt, 0, GFP_KERNEL);
>  }
>  EXPORT_SYMBOL(transport_init_session);
>  
> @@ -587,6 +595,7 @@ void transport_free_session(struct se_session *se_sess)
>  		sbitmap_queue_free(&se_sess->sess_tag_pool);
>  		kvfree(se_sess->sess_cmd_map);
>  	}
> +	percpu_ref_exit(&se_sess->cmd_count);
>  	kmem_cache_free(se_sess_cache, se_sess);
>  }
>  EXPORT_SYMBOL(transport_free_session);
> @@ -2730,6 +2739,7 @@ int target_get_sess_cmd(struct se_cmd *se_cmd, bool ack_kref)
>  	}
>  	se_cmd->transport_state |= CMD_T_PRE_EXECUTE;
>  	list_add_tail(&se_cmd->se_cmd_list, &se_sess->sess_cmd_list);
> +	percpu_ref_get(&se_sess->cmd_count);
>  out:
>  	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
>  

This would need to be a percpu_ref_tryget_live() before
CMD_T_PRE_EXECUTE is assigned, replacing the sess->sess_tearing_down
check.

> @@ -2760,8 +2770,6 @@ static void target_release_cmd_kref(struct kref *kref)
>  	if (se_sess) {
>  		spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
>  		list_del_init(&se_cmd->se_cmd_list);
> -		if (list_empty(&se_sess->sess_cmd_list))
> -			wake_up(&se_sess->cmd_list_wq);
>  		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
>  	}
>  

Btw, I noticed this small regression as part of your commit 00d909a1 in
mainline, seperate from this patch.

That is, for a iodepth=1 workload the new wake_up() above in
target_release_cmd_kref() is getting called every se_cmd->cmd_kref
release, even during the normal case when a session is not actually
being shutdown..

To address this for <= v4.19 separate from further changes:

diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 049a966..0473bf5 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -2760,7 +2760,7 @@ static void target_release_cmd_kref(struct kref *kref)
        if (se_sess) {
                spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
                list_del_init(&se_cmd->se_cmd_list);
-               if (list_empty(&se_sess->sess_cmd_list))
+               if (se_sess->sess_tearing_down && list_empty(&se_sess->sess_cmd_list))
                        wake_up(&se_sess->cmd_list_wq);
                spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
        }

I'll send it out separately for MKP to pick up.

> @@ -2769,6 +2777,8 @@ static void target_release_cmd_kref(struct kref *kref)
>  	se_cmd->se_tfo->release_cmd(se_cmd);
>  	if (compl)
>  		complete(compl);
> +
> +	percpu_ref_put(&se_sess->cmd_count);
>  }
>  
>  /**
> @@ -2897,6 +2907,8 @@ void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
>  	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
>  	se_sess->sess_tearing_down = 1;
>  	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
> +
> +	percpu_ref_kill_and_confirm(&se_sess->cmd_count, NULL);
>  }
>  EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
>  

Here is where percpu-ref and RCU grace-period magic comes in..

As a (future) consequence of relying solely upon se_sess->cmd_count, the
percpu_ref_kill_and_confirm() needs a percpu_ref->confirm_switch()
callback to work correctly, along with a matching local
wait_for_completion() within target_sess_cmd_list_set_waiting().

That is, the completion waits for percpu_ref_switch_to_atomic_rcu()
to call percpu_ref->confirm_switch() after a RCU grade-period has
elapsed so se_sess->cmd_count is seen as __PERCPU_REF_DEAD on all CPUs.

From there, se_sess->cmd_count is switched to atomic_t mode so that
percpu_ref_tryget_live() lookup of se_sess->cmd_count fails for all new
incoming I/O.

This is exactly how se_lun->lun_ref works today. See commit bd4e2d2907f
for more information.

> @@ -2911,17 +2923,14 @@ void target_wait_for_sess_cmds(struct se_session *se_sess)
>  
>  	WARN_ON_ONCE(!se_sess->sess_tearing_down);
>  
> -	spin_lock_irq(&se_sess->sess_cmd_lock);
>  	do {
> -		ret = wait_event_interruptible_lock_irq_timeout(
> -				se_sess->cmd_list_wq,
> -				list_empty(&se_sess->sess_cmd_list),
> -				se_sess->sess_cmd_lock, 180 * HZ);
> +		ret = wait_event_timeout(se_sess->cmd_list_wq,
> +				percpu_ref_is_zero(&se_sess->cmd_count),
> +				180 * HZ);
>  		list_for_each_entry(cmd, &se_sess->sess_cmd_list, se_cmd_list)
>  			target_show_cmd("session shutdown: still waiting for ",
>  					cmd);
>  	} while (ret <= 0);
> -	spin_unlock_irq(&se_sess->sess_cmd_lock);
>  }
>  EXPORT_SYMBOL(target_wait_for_sess_cmds);


It would be useful to move the hardcoded '180' into a tunable at some
point.

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough
  2018-09-17 21:35 [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough Bart Van Assche
  2018-10-06 12:05 ` Christoph Hellwig
  2018-10-07  3:28 ` Nicholas A. Bellinger
@ 2018-10-08 16:14 ` Bart Van Assche
  2018-10-08 16:32 ` Bart Van Assche
  3 siblings, 0 replies; 5+ messages in thread
From: Bart Van Assche @ 2018-10-08 16:14 UTC (permalink / raw)
  To: target-devel

On Sat, 2018-10-06 at 14:05 +-0200, Christoph Hellwig wrote:
+AD4 On Mon, Sep 17, 2018 at 02:35:42PM -0700, Bart Van Assche wrote:
+AD4 +AD4 A session must only be released after all code that accesses the session
+AD4 +AD4 structure has finished. Make sure that this is the case by introducing a
+AD4 +AD4 new command counter per session that is only decremented after the
+AD4 +AD4 .release+AF8-cmd() callback has finished.
+AD4 
+AD4 Can you explain what problems we are running into right now due to the
+AD4 lack of a refcount?

I will explain that further down in this e-mail.

+AD4 +AD4 +AEAAQA -2897,6 +-2907,8 +AEAAQA void target+AF8-sess+AF8-cmd+AF8-list+AF8-set+AF8-waiting(struct se+AF8-session +ACo-se+AF8-sess)
+AD4 +AD4  	spin+AF8-lock+AF8-irqsave(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4  	se+AF8-sess-+AD4-sess+AF8-tearing+AF8-down +AD0 1+ADs
+AD4 +AD4  	spin+AF8-unlock+AF8-irqrestore(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4 +-
+AD4 +AD4 +-	percpu+AF8-ref+AF8-kill+AF8-and+AF8-confirm(+ACY-se+AF8-sess-+AD4-cmd+AF8-count, NULL)+ADs
+AD4 
+AD4 This is equivalent ot a plain percpu+AF8-ref+AF8-kill call.

OK, I will change this into percpu+AF8-ref+AF8-kill().

+AD4 +AD4 +AEAAQA -2911,17 +-2923,14 +AEAAQA void target+AF8-wait+AF8-for+AF8-sess+AF8-cmds(struct se+AF8-session +ACo-se+AF8-sess)
+AD4 +AD4  
+AD4 +AD4  	WARN+AF8-ON+AF8-ONCE(+ACE-se+AF8-sess-+AD4-sess+AF8-tearing+AF8-down)+ADs
+AD4 +AD4  
+AD4 +AD4 -	spin+AF8-lock+AF8-irq(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock)+ADs
+AD4 +AD4  	do +AHs
+AD4 +AD4 -		ret +AD0 wait+AF8-event+AF8-interruptible+AF8-lock+AF8-irq+AF8-timeout(
+AD4 +AD4 -				se+AF8-sess-+AD4-cmd+AF8-list+AF8-wq,
+AD4 +AD4 -				list+AF8-empty(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-list),
+AD4 +AD4 -				se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, 180 +ACo HZ)+ADs
+AD4 +AD4 +-		ret +AD0 wait+AF8-event+AF8-timeout(se+AF8-sess-+AD4-cmd+AF8-list+AF8-wq,
+AD4 +AD4 +-				percpu+AF8-ref+AF8-is+AF8-zero(+ACY-se+AF8-sess-+AD4-cmd+AF8-count),
+AD4 +AD4 +-				180 +ACo HZ)+ADs
+AD4 
+AD4 So this is basically the big change - check for a zero reference instead
+AD4 of the list+AF8-empty.
+AD4 
+AD4 I fail to see how this makes a difference, and also why we even need a
+AD4 percpu ref as the get/pull calls are under, or right next to
+AD4 sess+AF8-cmd+AF8-lock critical sections.

Hi Christoph,

After having called target+AF8-wait+AF8-for+AF8-sess+AF8-cmds(), several target drivers call
target+AF8-remove+AF8-session(). That last function frees the session object
synchronously. In other words, it is not safe to use the session pointer after
target+AF8-wait+AF8-for+AF8-sess+AF8-cmds() has returned. That means that
target+AF8-wait+AF8-for+AF8-sess+AF8-cmds() must wait until all code that can dereference the
session pointer has finished, including target+AF8-release+AF8-cmd+AF8-kref(). That
function executes the following code after having removed a command from the
command list:

	target+AF8-free+AF8-cmd+AF8-mem(se+AF8-cmd)+ADs
	se+AF8-cmd-+AD4-se+AF8-tfo-+AD4-release+AF8-cmd(se+AF8-cmd)+ADs
	if (compl)
		complete(compl)+ADs

Hence this patch that makes target+AF8-wait+AF8-for+AF8-sess+AF8-cmds() wait until
target+AF8-release+AF8-cmd+AF8-kref() has called .release+AF8-cmd(). Since I applied this patch
I have not hit the following crash anymore:

BUG: KASAN: use-after-free in do+AF8-raw+AF8-spin+AF8-lock+-0x1c/0x130
Read of size 4 at addr ffff8801534b16e4 by task rmdir/14805
CPU: 16 PID: 14805 Comm: rmdir Not tainted 4.18.0-rc2-dbg+- +ACM-5
Call Trace:
dump+AF8-stack+-0xa4/0xf5
print+AF8-address+AF8-description+-0x6f/0x270
kasan+AF8-report+-0x241/0x360
+AF8AXw-asan+AF8-load4+-0x78/0x80
do+AF8-raw+AF8-spin+AF8-lock+-0x1c/0x130
+AF8-raw+AF8-spin+AF8-lock+AF8-irqsave+-0x52/0x60
srpt+AF8-set+AF8-ch+AF8-state+-0x27/0x70 +AFs-ib+AF8-srpt+AF0
srpt+AF8-disconnect+AF8-ch+-0x1b/0xc0 +AFs-ib+AF8-srpt+AF0
srpt+AF8-close+AF8-session+-0xa8/0x260 +AFs-ib+AF8-srpt+AF0
target+AF8-shutdown+AF8-sessions+-0x170/0x180 +AFs-target+AF8-core+AF8-mod+AF0
core+AF8-tpg+AF8-del+AF8-initiator+AF8-node+AF8-acl+-0xf3/0x200 +AFs-target+AF8-core+AF8-mod+AF0
target+AF8-fabric+AF8-nacl+AF8-base+AF8-release+-0x25/0x30 +AFs-target+AF8-core+AF8-mod+AF0
config+AF8-item+AF8-release+-0x9c/0x110 +AFs-configfs+AF0
config+AF8-item+AF8-put+-0x26/0x30 +AFs-configfs+AF0
configfs+AF8-rmdir+-0x3b8/0x510 +AFs-configfs+AF0
vfs+AF8-rmdir+-0xb3/0x1e0
do+AF8-rmdir+-0x262/0x2c0
do+AF8-syscall+AF8-64+-0x77/0x230
entry+AF8-SYSCALL+AF8-64+AF8-after+AF8-hwframe+-0x49/0xbe

Please let me know if you need more information.

Bart.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough
  2018-09-17 21:35 [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough Bart Van Assche
                   ` (2 preceding siblings ...)
  2018-10-08 16:14 ` Bart Van Assche
@ 2018-10-08 16:32 ` Bart Van Assche
  3 siblings, 0 replies; 5+ messages in thread
From: Bart Van Assche @ 2018-10-08 16:32 UTC (permalink / raw)
  To: target-devel

On Sat, 2018-10-06 at 20:28 -0700, Nicholas A. Bellinger wrote:
+AD4 On Mon, 2018-09-17 at 14:35 -0700, Bart Van Assche wrote:
+AD4 +AD4 diff --git a/drivers/target/target+AF8-core+AF8-transport.c b/drivers/target/target+AF8-core+AF8-transport.c
+AD4 +AD4 index 94e9d03af99d..54ccd8f56a57 100644
+AD4 +AD4 --- a/drivers/target/target+AF8-core+AF8-transport.c
+AD4 +AD4 +-+-+- b/drivers/target/target+AF8-core+AF8-transport.c
+AD4 +AD4 +AEAAQA -224,6 +-224,13 +AEAAQA void transport+AF8-subsystem+AF8-check+AF8-init(void)
+AD4 +AD4  	sub+AF8-api+AF8-initialized +AD0 1+ADs
+AD4 +AD4  +AH0
+AD4 +AD4  
+AD4 +AD4 +-static void target+AF8-release+AF8-sess+AF8-cmd+AF8-refcnt(struct percpu+AF8-ref +ACo-ref)
+AD4 +AD4 +-+AHs
+AD4 +AD4 +-	struct se+AF8-session +ACo-sess +AD0 container+AF8-of(ref, typeof(+ACo-sess), cmd+AF8-count)+ADs
+AD4 +AD4 +-
+AD4 +AD4 +-	wake+AF8-up(+ACY-sess-+AD4-cmd+AF8-list+AF8-wq)+ADs
+AD4 +AD4 +-+AH0
+AD4 +AD4 +-
+AD4 +AD4  /+ACoAKg
+AD4 +AD4   +ACo transport+AF8-init+AF8-session - initialize a session object
+AD4 +AD4   +ACo +AEA-se+AF8-sess: Session object pointer.
+AD4 +AD4 +AEAAQA -237,7 +-244,8 +AEAAQA int transport+AF8-init+AF8-session(struct se+AF8-session +ACo-se+AF8-sess)
+AD4 +AD4  	INIT+AF8-LIST+AF8-HEAD(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-list)+ADs
+AD4 +AD4  	spin+AF8-lock+AF8-init(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock)+ADs
+AD4 +AD4  	init+AF8-waitqueue+AF8-head(+ACY-se+AF8-sess-+AD4-cmd+AF8-list+AF8-wq)+ADs
+AD4 +AD4 -	return 0+ADs
+AD4 +AD4 +-	return percpu+AF8-ref+AF8-init(+ACY-se+AF8-sess-+AD4-cmd+AF8-count,
+AD4 +AD4 +-			       target+AF8-release+AF8-sess+AF8-cmd+AF8-refcnt, 0, GFP+AF8-KERNEL)+ADs
+AD4 +AD4  +AH0
+AD4 +AD4  EXPORT+AF8-SYMBOL(transport+AF8-init+AF8-session)+ADs
+AD4 +AD4  
+AD4 +AD4 +AEAAQA -587,6 +-595,7 +AEAAQA void transport+AF8-free+AF8-session(struct se+AF8-session +ACo-se+AF8-sess)
+AD4 +AD4  		sbitmap+AF8-queue+AF8-free(+ACY-se+AF8-sess-+AD4-sess+AF8-tag+AF8-pool)+ADs
+AD4 +AD4  		kvfree(se+AF8-sess-+AD4-sess+AF8-cmd+AF8-map)+ADs
+AD4 +AD4  	+AH0
+AD4 +AD4 +-	percpu+AF8-ref+AF8-exit(+ACY-se+AF8-sess-+AD4-cmd+AF8-count)+ADs
+AD4 +AD4  	kmem+AF8-cache+AF8-free(se+AF8-sess+AF8-cache, se+AF8-sess)+ADs
+AD4 +AD4  +AH0
+AD4 +AD4  EXPORT+AF8-SYMBOL(transport+AF8-free+AF8-session)+ADs
+AD4 +AD4 +AEAAQA -2730,6 +-2739,7 +AEAAQA int target+AF8-get+AF8-sess+AF8-cmd(struct se+AF8-cmd +ACo-se+AF8-cmd, bool ack+AF8-kref)
+AD4 +AD4  	+AH0
+AD4 +AD4  	se+AF8-cmd-+AD4-transport+AF8-state +AHwAPQ CMD+AF8-T+AF8-PRE+AF8-EXECUTE+ADs
+AD4 +AD4  	list+AF8-add+AF8-tail(+ACY-se+AF8-cmd-+AD4-se+AF8-cmd+AF8-list, +ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-list)+ADs
+AD4 +AD4 +-	percpu+AF8-ref+AF8-get(+ACY-se+AF8-sess-+AD4-cmd+AF8-count)+ADs
+AD4 +AD4  out:
+AD4 +AD4  	spin+AF8-unlock+AF8-irqrestore(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4  
+AD4 
+AD4 This would need to be a percpu+AF8-ref+AF8-tryget+AF8-live() before
+AD4 CMD+AF8-T+AF8-PRE+AF8-EXECUTE is assigned, replacing the sess-+AD4-sess+AF8-tearing+AF8-down
+AD4 check.

I think the current code is fine since the percpu+AF8-ref+AF8-get() call happens
with the sess+AF8-cmd+AF8-lock held and after the sess+AF8-tearing+AF8-down flag has been
checked. The spinlock is needed anyway to protect the list+AF8-add+AF8-tail() call.
Let's keep the discussion about dropping se+AF8-cmd+AF8-list and switching to
sbitmap instead for later because this patch series is already complicated
enough and also because I'm not convinced that that switching to an sbitmap
would be an improvement.

+AD4 +AD4 +AEAAQA -2769,6 +-2777,8 +AEAAQA static void target+AF8-release+AF8-cmd+AF8-kref(struct kref +ACo-kref)
+AD4 +AD4  	se+AF8-cmd-+AD4-se+AF8-tfo-+AD4-release+AF8-cmd(se+AF8-cmd)+ADs
+AD4 +AD4  	if (compl)
+AD4 +AD4  		complete(compl)+ADs
+AD4 +AD4 +-
+AD4 +AD4 +-	percpu+AF8-ref+AF8-put(+ACY-se+AF8-sess-+AD4-cmd+AF8-count)+ADs
+AD4 +AD4  +AH0
+AD4 +AD4  
+AD4 +AD4  /+ACoAKg
+AD4 +AD4 +AEAAQA -2897,6 +-2907,8 +AEAAQA void target+AF8-sess+AF8-cmd+AF8-list+AF8-set+AF8-waiting(struct se+AF8-session +ACo-se+AF8-sess)
+AD4 +AD4  	spin+AF8-lock+AF8-irqsave(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4  	se+AF8-sess-+AD4-sess+AF8-tearing+AF8-down +AD0 1+ADs
+AD4 +AD4  	spin+AF8-unlock+AF8-irqrestore(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4 +-
+AD4 +AD4 +-	percpu+AF8-ref+AF8-kill+AF8-and+AF8-confirm(+ACY-se+AF8-sess-+AD4-cmd+AF8-count, NULL)+ADs
+AD4 +AD4  +AH0
+AD4 +AD4  EXPORT+AF8-SYMBOL(target+AF8-sess+AF8-cmd+AF8-list+AF8-set+AF8-waiting)+ADs
+AD4 +AD4  
+AD4 
+AD4 Here is where percpu-ref and RCU grace-period magic comes in..
+AD4 
+AD4 As a (future) consequence of relying solely upon se+AF8-sess-+AD4-cmd+AF8-count, the
+AD4 percpu+AF8-ref+AF8-kill+AF8-and+AF8-confirm() needs a percpu+AF8-ref-+AD4-confirm+AF8-switch()
+AD4 callback to work correctly, along with a matching local
+AD4 wait+AF8-for+AF8-completion() within target+AF8-sess+AF8-cmd+AF8-list+AF8-set+AF8-waiting().

I do not agree. A session is only freed after target+AF8-wait+AF8-for+AF8-sess+AF8-cmds()
has returned so it is sufficient if that function waits until the switch
to atomic mode of the percpu-refcount has finished. I don't see why
target+AF8-sess+AF8-cmd+AF8-list+AF8-set+AF8-waiting() should wait until the switch to atomic
mode has finished.

Bart.

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2018-10-08 16:32 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-17 21:35 [PATCH 05/17] target/core: Make sure that target_wait_for_sess_cmds() waits long enough Bart Van Assche
2018-10-06 12:05 ` Christoph Hellwig
2018-10-07  3:28 ` Nicholas A. Bellinger
2018-10-08 16:14 ` Bart Van Assche
2018-10-08 16:32 ` Bart Van Assche

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.