Re: [PATCH 10/21] target: Free session objects after associated commands have finished

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



I had to implement some similar infrastucture recently, so a few
late comments:

> The reason your hitting this is because FCoE target doesn't use
> target_sess_cmd_list_set_waiting() + target_wait_for_sess_cmds() during
> se_session shutdown, which target_submit_cmd() + target_submit_tmr()
> depends on for checking se_session->sess_tearing_down, and why
> target_release_cmd_kref() does complete(&se_cmd->cmd_wait_comp);

Needing an explicit shutdown and drain call during shutdown seems
like an unfortunate design choice.  I think everyone would be
better off having an implicit wait that ensures no commands are
outstanding during shutdown.

> So really, this needs to be a BUG_ON(!list_empty()) for sess_cmd_list +
> sess_wait_list in transport_free_session(), and FCoE target needs to be
> converted to use these primitives following tcm_qla2xxx, ib_isert, and
> ib_srpt function.
> 
> Adding a hack for FCoE target is not going to cut it.
> 
> > @@ -2524,6 +2531,8 @@ static void target_release_cmd_kref(struct kref *kref)
> >  		return;
> >  	}
> >  	list_del(&se_cmd->se_cmd_list);
> > +	if (list_empty(&se_cmd->se_cmd_list))
> > +		wake_up(&se_sess->cmd_list_wq);
> >  	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
> >  
> >  	se_cmd->se_tfo->release_cmd(se_cmd);
> 
> Unnecessary fast-path wake-up for every I/O.  No thanks.

I think this should be a list_empty(&se_sess->sess_cmd_list),
which would not be once per I/O.

Otherwise I agree there should just be one place to wait for shutdown,
but even if that once place is target_wait_for_sess_cmds it would
benefit from using the more efficient algorithm in Bart's patch.

Something like the untested patch below (on top of this series):


diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c
index 8b0ea56..11eba9f 100644
--- a/drivers/target/target_core_transport.c
+++ b/drivers/target/target_core_transport.c
@@ -237,7 +237,6 @@ struct se_session *transport_init_session(enum target_prot_op sup_prot_ops)
 	INIT_LIST_HEAD(&se_sess->sess_list);
 	INIT_LIST_HEAD(&se_sess->sess_acl_list);
 	INIT_LIST_HEAD(&se_sess->sess_cmd_list);
-	INIT_LIST_HEAD(&se_sess->sess_wait_list);
 	spin_lock_init(&se_sess->sess_cmd_lock);
 	init_waitqueue_head(&se_sess->cmd_list_wq);
 	kref_init(&se_sess->sess_kref);
@@ -465,12 +464,6 @@ EXPORT_SYMBOL(transport_deregister_session_configfs);
 
 void transport_free_session(struct se_session *se_sess)
 {
-	spin_lock_irq(&se_sess->sess_cmd_lock);
-	wait_event_lock_irq(se_sess->cmd_list_wq,
-			    list_empty(&se_sess->sess_cmd_list),
-			    se_sess->sess_cmd_lock);
-	spin_unlock_irq(&se_sess->sess_cmd_lock);
-
 	if (se_sess->sess_cmd_map) {
 		percpu_ida_destroy(&se_sess->sess_tag_pool);
 		kvfree(se_sess->sess_cmd_map);
@@ -1165,7 +1158,6 @@ void transport_init_se_cmd(
 	INIT_LIST_HEAD(&cmd->se_qf_node);
 	INIT_LIST_HEAD(&cmd->se_cmd_list);
 	INIT_LIST_HEAD(&cmd->state_list);
-	init_completion(&cmd->cmd_wait_comp);
 	init_completion(&cmd->finished);
 	spin_lock_init(&cmd->t_state_lock);
 	kref_init(&cmd->cmd_kref);
@@ -2458,19 +2450,11 @@ static void target_release_cmd_kref(struct kref *kref)
 	unsigned long flags;
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-	if (list_empty(&se_cmd->se_cmd_list)) {
-		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-		se_cmd->se_tfo->release_cmd(se_cmd);
-		return;
-	}
-	if (se_sess->sess_tearing_down && se_cmd->cmd_wait_set) {
-		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-		complete(&se_cmd->cmd_wait_comp);
-		return;
+	if (!list_empty(&se_cmd->se_cmd_list)) {
+		list_del(&se_cmd->se_cmd_list);
+		if (list_empty(&se_sess->sess_cmd_list))
+			wake_up(&se_sess->cmd_list_wq);
 	}
-	list_del(&se_cmd->se_cmd_list);
-	if (list_empty(&se_cmd->se_cmd_list))
-		wake_up(&se_sess->cmd_list_wq);
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 
 	se_cmd->se_tfo->release_cmd(se_cmd);
@@ -2491,59 +2475,35 @@ int target_put_sess_cmd(struct se_cmd *se_cmd)
 }
 EXPORT_SYMBOL(target_put_sess_cmd);
 
-/* target_sess_cmd_list_set_waiting - Flag all commands in
- *         sess_cmd_list to complete cmd_wait_comp.  Set
- *         sess_tearing_down so no more commands are queued.
+/**
+ * target_sess_cmd_list_set_waiting - stop processing of new commands
  * @se_sess:	session to flag
+ *
+ * Prevent new commands from being queued on this session.  The caller should
+ * then use target_wait_for_sess_cmds to wait for all outstanding commands to
+ * be processed.
  */
 void target_sess_cmd_list_set_waiting(struct se_session *se_sess)
 {
-	struct se_cmd *se_cmd;
 	unsigned long flags;
 
 	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-	if (se_sess->sess_tearing_down) {
-		spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-		return;
-	}
 	se_sess->sess_tearing_down = 1;
-	list_splice_init(&se_sess->sess_cmd_list, &se_sess->sess_wait_list);
-
-	list_for_each_entry(se_cmd, &se_sess->sess_wait_list, se_cmd_list)
-		se_cmd->cmd_wait_set = 1;
-
 	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
 }
 EXPORT_SYMBOL(target_sess_cmd_list_set_waiting);
 
-/* target_wait_for_sess_cmds - Wait for outstanding descriptors
+/**
+ * target_wait_for_sess_cmds - Wait for outstanding descriptors
  * @se_sess:    session to wait for active I/O
  */
 void target_wait_for_sess_cmds(struct se_session *se_sess)
 {
-	struct se_cmd *se_cmd, *tmp_cmd;
-	unsigned long flags;
-
-	list_for_each_entry_safe(se_cmd, tmp_cmd,
-				&se_sess->sess_wait_list, se_cmd_list) {
-		list_del(&se_cmd->se_cmd_list);
-
-		pr_debug("Waiting for se_cmd: %p t_state: %d, fabric state:"
-			" %d\n", se_cmd, se_cmd->t_state,
-			se_cmd->se_tfo->get_cmd_state(se_cmd));
-
-		wait_for_completion(&se_cmd->cmd_wait_comp);
-		pr_debug("After cmd_wait_comp: se_cmd: %p t_state: %d"
-			" fabric state: %d\n", se_cmd, se_cmd->t_state,
-			se_cmd->se_tfo->get_cmd_state(se_cmd));
-
-		se_cmd->se_tfo->release_cmd(se_cmd);
-	}
-
-	spin_lock_irqsave(&se_sess->sess_cmd_lock, flags);
-	WARN_ON(!list_empty(&se_sess->sess_cmd_list));
-	spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags);
-
+	spin_lock_irq(&se_sess->sess_cmd_lock);
+	wait_event_lock_irq(se_sess->cmd_list_wq,
+			    list_empty(&se_sess->sess_cmd_list),
+			    se_sess->sess_cmd_lock);
+	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 94d9697..d44551a 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -438,7 +438,6 @@ struct se_cmd {
 	u8			scsi_asc;
 	u8			scsi_ascq;
 	u16			scsi_sense_length;
-	unsigned		cmd_wait_set:1;
 	unsigned		unknown_data_length:1;
 	bool			state_active:1;
 	unsigned		send_abort_response:1;
@@ -471,7 +470,6 @@ struct se_cmd {
 	struct se_session	*se_sess;
 	struct se_tmr_req	*se_tmr_req;
 	struct list_head	se_cmd_list;
-	struct completion	cmd_wait_comp;
 	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);
@@ -597,7 +595,6 @@ struct se_session {
 	struct list_head	sess_list;
 	struct list_head	sess_acl_list;
 	struct list_head	sess_cmd_list;
-	struct list_head	sess_wait_list;
 	spinlock_t		sess_cmd_lock;
 	wait_queue_head_t	cmd_list_wq;
 	struct kref		sess_kref;
--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux SCSI]     [Kernel Newbies]     [Linux SCSI Target Infrastructure]     [Share Photos]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Device Mapper]

  Powered by Linux