* [PATCH 10/17] target/core: Make it possible to wait from more than one context for command completio
@ 2018-09-17 21:35 Bart Van Assche
2018-10-07 3:44 ` [PATCH 10/17] target/core: Make it possible to wait from more than one context for command compl Nicholas A. Bellinger
2018-10-08 18:02 ` Bart Van Assche
0 siblings, 2 replies; 3+ messages in thread
From: Bart Van Assche @ 2018-09-17 21:35 UTC (permalink / raw)
To: target-devel
This patch does not change any functionality but makes the next patch
easier to read.
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 | 69 ++++++++++++++++++++++----
include/target/target_core_base.h | 2 +-
2 files changed, 60 insertions(+), 11 deletions(-)
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 79fa79afcdc2..1fecd2bb53af 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -1331,7 +1331,7 @@ void transport_init_se_cmd(
INIT_LIST_HEAD(&cmd->se_cmd_list);
INIT_LIST_HEAD(&cmd->state_list);
init_completion(&cmd->t_transport_stop_comp);
- cmd->compl = NULL;
+ init_waitqueue_head(&cmd->release_wq);
spin_lock_init(&cmd->t_state_lock);
INIT_WORK(&cmd->work, NULL);
kref_init(&cmd->cmd_kref);
@@ -2649,6 +2649,47 @@ static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
spin_unlock_irqrestore(&cmd->t_state_lock, flags);
}
+static void __target_put_cmd_and_wait(struct se_cmd *cmd, bool put)
+{
+ DEFINE_WAIT(wait);
+ long ret;
+
+ prepare_to_wait(&cmd->release_wq, &wait, TASK_UNINTERRUPTIBLE);
+ if (put)
+ target_put_sess_cmd(cmd);
+ for (;;) {
+ if (list_empty_careful(&wait.entry))
+ break;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ if (list_empty_careful(&wait.entry)) {
+ set_current_state(TASK_RUNNING);
+ break;
+ }
+ ret = schedule_timeout(180 * HZ);
+ if (ret = 0)
+ target_show_cmd("still waiting for ", cmd);
+ }
+}
+
+/*
+ * Call target_put_sess_cmd() and wait until target_release_cmd_kref(@cmd) has
+ * finished.
+ */
+static void target_put_cmd_and_wait(struct se_cmd *cmd)
+{
+ __target_put_cmd_and_wait(cmd, true);
+}
+
+/*
+ * Wait until target_release_cmd_kref(@cmd) has finished. Calling this function
+ * is only safe if the release function does not free the memory allocated for
+ * @cmd. This is e.g. the case for the iSCSI target driver.
+ */
+static void target_wait_for_cmd(struct se_cmd *cmd)
+{
+ __target_put_cmd_and_wait(cmd, false);
+}
+
/*
* This function is called by frontend drivers after processing of a command
* has finished.
@@ -2672,7 +2713,6 @@ static void target_wait_free_cmd(struct se_cmd *cmd, bool *aborted, bool *tas)
*/
int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
{
- DECLARE_COMPLETION_ONSTACK(compl);
int ret = 0;
bool aborted = false, tas = false;
@@ -2691,14 +2731,17 @@ int transport_generic_free_cmd(struct se_cmd *cmd, int wait_for_tasks)
if (cmd->se_lun)
transport_lun_remove_cmd(cmd);
}
- if (aborted)
- cmd->compl = &compl;
- if (!aborted || tas)
- ret = target_put_sess_cmd(cmd);
if (aborted) {
pr_debug("Detected CMD_T_ABORTED for ITT: %llu\n", cmd->tag);
- wait_for_completion(&compl);
+ if (tas) {
+ target_put_cmd_and_wait(cmd);
+ } else {
+ WARN_ON_ONCE(!wait_for_tasks);
+ target_wait_for_cmd(cmd);
+ }
ret = 1;
+ } else {
+ ret = target_put_sess_cmd(cmd);
}
return ret;
}
@@ -2759,9 +2802,16 @@ static void target_release_cmd_kref(struct kref *kref)
{
struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
struct se_session *se_sess = se_cmd->se_sess;
- struct completion *compl = se_cmd->compl;
+ struct wait_queue_head release_wq;
unsigned long flags;
+ init_waitqueue_head(&release_wq);
+ /*
+ * No locking is required since we are in the release function and
+ * adding to release_wq is only allowed while holding a reference.
+ */
+ list_splice_init(&se_cmd->release_wq.head, &release_wq.head);
+
if (se_sess) {
spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
list_del_init(&se_cmd->se_cmd_list);
@@ -2770,8 +2820,7 @@ static void target_release_cmd_kref(struct kref *kref)
target_free_cmd_mem(se_cmd);
se_cmd->se_tfo->release_cmd(se_cmd);
- if (compl)
- complete(compl);
+ wake_up_all(&release_wq);
percpu_ref_put(&se_sess->cmd_count);
}
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index d084479fbe18..d93ec20710c2 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -475,7 +475,7 @@ struct se_cmd {
struct se_session *se_sess;
struct se_tmr_req *se_tmr_req;
struct list_head se_cmd_list;
- struct completion *compl;
+ struct wait_queue_head release_wq;
const struct target_core_fabric_ops *se_tfo;
sense_reason_t (*execute_cmd)(struct se_cmd *);
sense_reason_t (*transport_complete_callback)(struct se_cmd *, bool, int *);
--
2.18.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH 10/17] target/core: Make it possible to wait from more than one context for command compl
2018-09-17 21:35 [PATCH 10/17] target/core: Make it possible to wait from more than one context for command completio Bart Van Assche
@ 2018-10-07 3:44 ` Nicholas A. Bellinger
2018-10-08 18:02 ` Bart Van Assche
1 sibling, 0 replies; 3+ messages in thread
From: Nicholas A. Bellinger @ 2018-10-07 3:44 UTC (permalink / raw)
To: target-devel
On Mon, 2018-09-17 at 14:35 -0700, Bart Van Assche wrote:
> This patch does not change any functionality but makes the next patch
> easier to read.
>
> 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 | 69 ++++++++++++++++++++++----
> include/target/target_core_base.h | 2 +-
> 2 files changed, 60 insertions(+), 11 deletions(-)
>
<SNIP>
> @@ -2759,9 +2802,16 @@ static void target_release_cmd_kref(struct kref *kref)
> {
> struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref);
> struct se_session *se_sess = se_cmd->se_sess;
> - struct completion *compl = se_cmd->compl;
> + struct wait_queue_head release_wq;
> unsigned long flags;
>
> + init_waitqueue_head(&release_wq);
> + /*
> + * No locking is required since we are in the release function and
> + * adding to release_wq is only allowed while holding a reference.
> + */
> + list_splice_init(&se_cmd->release_wq.head, &release_wq.head);
> +
> if (se_sess) {
> spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
> list_del_init(&se_cmd->se_cmd_list);
> @@ -2770,8 +2820,7 @@ static void target_release_cmd_kref(struct kref *kref)
>
> target_free_cmd_mem(se_cmd);
> se_cmd->se_tfo->release_cmd(se_cmd);
> - if (compl)
> - complete(compl);
> + wake_up_all(&release_wq);
>
> percpu_ref_put(&se_sess->cmd_count);
> }
Your earlier commit 7b2cc7dc0 in mainline to use a local stack compl in
transport_generic_free_cmd() was a reasonable change, because fast-path
code in target_release_cmd_kref() was only doing a complete() when the
se_cmd was actually being quiesced..
However, the addition of wake_up_all() above for every se_cmd means a
__wake_up_common_lock() happens no matter what every time in fast-path
code.
Please, don't do this.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH 10/17] target/core: Make it possible to wait from more than one context for command compl
2018-09-17 21:35 [PATCH 10/17] target/core: Make it possible to wait from more than one context for command completio Bart Van Assche
2018-10-07 3:44 ` [PATCH 10/17] target/core: Make it possible to wait from more than one context for command compl Nicholas A. Bellinger
@ 2018-10-08 18:02 ` Bart Van Assche
1 sibling, 0 replies; 3+ messages in thread
From: Bart Van Assche @ 2018-10-08 18:02 UTC (permalink / raw)
To: target-devel
On Sat, 2018-10-06 at 20:44 -0700, Nicholas A. Bellinger wrote:
+AD4 On Mon, 2018-09-17 at 14:35 -0700, Bart Van Assche wrote:
+AD4 +AD4 +AEAAQA -2759,9 +-2802,16 +AEAAQA static void target+AF8-release+AF8-cmd+AF8-kref(struct kref +ACo-kref)
+AD4 +AD4 +AHs
+AD4 +AD4 struct se+AF8-cmd +ACo-se+AF8-cmd +AD0 container+AF8-of(kref, struct se+AF8-cmd, cmd+AF8-kref)+ADs
+AD4 +AD4 struct se+AF8-session +ACo-se+AF8-sess +AD0 se+AF8-cmd-+AD4-se+AF8-sess+ADs
+AD4 +AD4 - struct completion +ACo-compl +AD0 se+AF8-cmd-+AD4-compl+ADs
+AD4 +AD4 +- struct wait+AF8-queue+AF8-head release+AF8-wq+ADs
+AD4 +AD4 unsigned long flags+ADs
+AD4 +AD4
+AD4 +AD4 +- init+AF8-waitqueue+AF8-head(+ACY-release+AF8-wq)+ADs
+AD4 +AD4 +- /+ACo
+AD4 +AD4 +- +ACo No locking is required since we are in the release function and
+AD4 +AD4 +- +ACo adding to release+AF8-wq is only allowed while holding a reference.
+AD4 +AD4 +- +ACo-/
+AD4 +AD4 +- list+AF8-splice+AF8-init(+ACY-se+AF8-cmd-+AD4-release+AF8-wq.head, +ACY-release+AF8-wq.head)+ADs
+AD4 +AD4 +-
+AD4 +AD4 if (se+AF8-sess) +AHs
+AD4 +AD4 spin+AF8-lock+AF8-irqsave(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
+AD4 +AD4 list+AF8-del+AF8-init(+ACY-se+AF8-cmd-+AD4-se+AF8-cmd+AF8-list)+ADs
+AD4 +AD4 +AEAAQA -2770,8 +-2820,7 +AEAAQA static void target+AF8-release+AF8-cmd+AF8-kref(struct kref +ACo-kref)
+AD4 +AD4
+AD4 +AD4 target+AF8-free+AF8-cmd+AF8-mem(se+AF8-cmd)+ADs
+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 +- wake+AF8-up+AF8-all(+ACY-release+AF8-wq)+ADs
+AD4 +AD4
+AD4 +AD4 percpu+AF8-ref+AF8-put(+ACY-se+AF8-sess-+AD4-cmd+AF8-count)+ADs
+AD4 +AD4 +AH0
+AD4
+AD4 Your earlier commit 7b2cc7dc0 in mainline to use a local stack compl in
+AD4 transport+AF8-generic+AF8-free+AF8-cmd() was a reasonable change, because fast-path
+AD4 code in target+AF8-release+AF8-cmd+AF8-kref() was only doing a complete() when the
+AD4 se+AF8-cmd was actually being quiesced..
+AD4
+AD4 However, the addition of wake+AF8-up+AF8-all() above for every se+AF8-cmd means a
+AD4 +AF8AXw-wake+AF8-up+AF8-common+AF8-lock() happens no matter what every time in fast-path
+AD4 code.
That's easy to fix. How about replacing this patch with the following patch?
+AFs-PATCH+AF0 target/core: Make it possible to wait from more than one context for command completion
This patch does not change any functionality but makes the next patch
easier to read.
Signed-off-by: Bart Van Assche +ADw-bvanassche+AEA-acm.org+AD4
Cc: Nicholas Bellinger +ADw-nab+AEA-linux-iscsi.org+AD4
Cc: Mike Christie +ADw-mchristi+AEA-redhat.com+AD4
Cc: Christoph Hellwig +ADw-hch+AEA-lst.de+AD4
Cc: Hannes Reinecke +ADw-hare+AEA-suse.de+AD4
---
drivers/target/target+AF8-core+AF8-transport.c +AHw 15 +-+-+-+-+-+-+-+-+-+------
include/target/target+AF8-core+AF8-base.h +AHw 2 +--
2 files changed, 11 insertions(+-), 6 deletions(-)
diff --git a/drivers/target/target+AF8-core+AF8-transport.c b/drivers/target/target+AF8-core+AF8-transport.c
index 79fa79afcdc2..de54494cf98f 100644
--- a/drivers/target/target+AF8-core+AF8-transport.c
+-+-+- b/drivers/target/target+AF8-core+AF8-transport.c
+AEAAQA -1331,7 +-1331,7 +AEAAQA void transport+AF8-init+AF8-se+AF8-cmd(
INIT+AF8-LIST+AF8-HEAD(+ACY-cmd-+AD4-se+AF8-cmd+AF8-list)+ADs
INIT+AF8-LIST+AF8-HEAD(+ACY-cmd-+AD4-state+AF8-list)+ADs
init+AF8-completion(+ACY-cmd-+AD4-t+AF8-transport+AF8-stop+AF8-comp)+ADs
- cmd-+AD4-compl +AD0 NULL+ADs
+- memset(cmd-+AD4-compl, 0, sizeof(cmd-+AD4-compl))+ADs
spin+AF8-lock+AF8-init(+ACY-cmd-+AD4-t+AF8-state+AF8-lock)+ADs
INIT+AF8-WORK(+ACY-cmd-+AD4-work, NULL)+ADs
kref+AF8-init(+ACY-cmd-+AD4-cmd+AF8-kref)+ADs
+AEAAQA -2692,7 +-2692,7 +AEAAQA int transport+AF8-generic+AF8-free+AF8-cmd(struct se+AF8-cmd +ACo-cmd, int wait+AF8-for+AF8-tasks)
transport+AF8-lun+AF8-remove+AF8-cmd(cmd)+ADs
+AH0
if (aborted)
- cmd-+AD4-compl +AD0 +ACY-compl+ADs
+- cmd-+AD4-compl+AFs-0+AF0 +AD0 +ACY-compl+ADs
if (+ACE-aborted +AHwAfA tas)
ret +AD0 target+AF8-put+AF8-sess+AF8-cmd(cmd)+ADs
if (aborted) +AHs
+AEAAQA -2759,9 +-2759,12 +AEAAQA static void target+AF8-release+AF8-cmd+AF8-kref(struct kref +ACo-kref)
+AHs
struct se+AF8-cmd +ACo-se+AF8-cmd +AD0 container+AF8-of(kref, struct se+AF8-cmd, cmd+AF8-kref)+ADs
struct se+AF8-session +ACo-se+AF8-sess +AD0 se+AF8-cmd-+AD4-se+AF8-sess+ADs
- struct completion +ACo-compl +AD0 se+AF8-cmd-+AD4-compl+ADs
+- struct completion +ACo-compl+AFs-2+AF0AOw
unsigned long flags+ADs
+- BUILD+AF8-BUG+AF8-ON(sizeof(compl) +ACEAPQ sizeof(se+AF8-cmd-+AD4-compl))+ADs
+- memcpy(compl, se+AF8-cmd-+AD4-compl, sizeof(compl))+ADs
+-
if (se+AF8-sess) +AHs
spin+AF8-lock+AF8-irqsave(+ACY-se+AF8-sess-+AD4-sess+AF8-cmd+AF8-lock, flags)+ADs
list+AF8-del+AF8-init(+ACY-se+AF8-cmd-+AD4-se+AF8-cmd+AF8-list)+ADs
+AEAAQA -2770,8 +-2773,10 +AEAAQA static void target+AF8-release+AF8-cmd+AF8-kref(struct kref +ACo-kref)
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
+- if (compl+AFs-0+AF0)
+- complete(compl+AFs-0+AF0)+ADs
+- if (compl+AFs-1+AF0)
+- complete(compl+AFs-1+AF0)+ADs
percpu+AF8-ref+AF8-put(+ACY-se+AF8-sess-+AD4-cmd+AF8-count)+ADs
+AH0
diff --git a/include/target/target+AF8-core+AF8-base.h b/include/target/target+AF8-core+AF8-base.h
index d084479fbe18..34c9a8ffa4af 100644
--- a/include/target/target+AF8-core+AF8-base.h
+-+-+- b/include/target/target+AF8-core+AF8-base.h
+AEAAQA -475,7 +-475,7 +AEAAQA struct se+AF8-cmd +AHs
struct se+AF8-session +ACo-se+AF8-sess+ADs
struct se+AF8-tmr+AF8-req +ACo-se+AF8-tmr+AF8-req+ADs
struct list+AF8-head se+AF8-cmd+AF8-list+ADs
- struct completion +ACo-compl+ADs
+- struct completion +ACo-compl+AFs-2+AF0AOw
const struct target+AF8-core+AF8-fabric+AF8-ops +ACo-se+AF8-tfo+ADs
sense+AF8-reason+AF8-t (+ACo-execute+AF8-cmd)(struct se+AF8-cmd +ACo)+ADs
sense+AF8-reason+AF8-t (+ACo-transport+AF8-complete+AF8-callback)(struct se+AF8-cmd +ACo, bool, int +ACo)+ADs
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2018-10-08 18:02 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-09-17 21:35 [PATCH 10/17] target/core: Make it possible to wait from more than one context for command completio Bart Van Assche
2018-10-07 3:44 ` [PATCH 10/17] target/core: Make it possible to wait from more than one context for command compl Nicholas A. Bellinger
2018-10-08 18:02 ` 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.