Instead of setting up a callback to execute retries after a QUEUE_FULL add a SCF_QUEUE_FULL flag that tells the normal worker routines that they are retrying a command they have seen before. Signed-off-by: Christoph Hellwig <hch@xxxxxx> Index: lio-core/drivers/target/target_core_transport.c =================================================================== --- lio-core.orig/drivers/target/target_core_transport.c 2011-10-12 17:05:49.549271375 +0200 +++ lio-core/drivers/target/target_core_transport.c 2011-10-12 17:05:52.498271150 +0200 @@ -74,8 +74,7 @@ static int transport_processing_thread(v static int __transport_execute_tasks(struct se_device *dev); static void transport_complete_task_attr(struct se_cmd *cmd); static int transport_complete_qf(struct se_cmd *cmd); -static void transport_handle_queue_full(struct se_cmd *cmd, - struct se_device *dev, int (*qf_callback)(struct se_cmd *)); +static void transport_handle_queue_full(struct se_cmd *cmd); static void transport_direct_request_timeout(struct se_cmd *cmd); static void transport_free_dev_tasks(struct se_cmd *cmd); static u32 transport_allocate_tasks(struct se_cmd *cmd, @@ -1936,7 +1935,7 @@ check_stop: queue_full: cmd->t_state = TRANSPORT_COMPLETE_OK; - transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf); + transport_handle_queue_full(cmd); } static void transport_direct_request_timeout(struct se_cmd *cmd) @@ -3426,10 +3425,7 @@ static int transport_complete_qf(struct return ret; } -static void transport_handle_queue_full( - struct se_cmd *cmd, - struct se_device *dev, - int (*qf_callback)(struct se_cmd *)) +static void transport_handle_queue_full(struct se_cmd *cmd) { pr_debug("Processing %s cmd: %p QUEUE_FULL %s", cmd->se_tfo->get_fabric_name(), cmd, @@ -3438,7 +3434,7 @@ static void transport_handle_queue_full( : "UNKNOWN"); spin_lock_irq(&cmd->t_state_lock); - cmd->transport_qf_callback = qf_callback; + cmd->se_cmd_flags |= SCF_QUEUE_FULL; spin_unlock_irq(&cmd->t_state_lock); __transport_add_cmd_to_queue(cmd, cmd->t_state, true); @@ -3455,12 +3451,14 @@ static void transport_generic_complete_o if (cmd->se_dev->dev_task_attr_type == SAM_TASK_ATTR_EMULATED) transport_complete_task_attr(cmd); - if (cmd->transport_qf_callback) { - ret = cmd->transport_qf_callback(cmd); + if (cmd->se_cmd_flags & SCF_QUEUE_FULL) { + spin_lock_irq(&cmd->t_state_lock); + cmd->se_cmd_flags &= SCF_QUEUE_FULL; + spin_unlock_irq(&cmd->t_state_lock); + + ret = transport_complete_qf(cmd); if (ret < 0) goto queue_full; - - cmd->transport_qf_callback = NULL; goto done; } /* @@ -3546,7 +3544,7 @@ done: queue_full: pr_debug("Handling complete_ok QUEUE_FULL: se_cmd: %p," " data_direction: %d\n", cmd, cmd->data_direction); - transport_handle_queue_full(cmd, cmd->se_dev, transport_complete_qf); + transport_handle_queue_full(cmd); } static void transport_free_dev_tasks(struct se_cmd *cmd) @@ -4073,11 +4071,6 @@ void transport_generic_process_write(str } EXPORT_SYMBOL(transport_generic_process_write); -static int transport_write_pending_qf(struct se_cmd *cmd) -{ - return cmd->se_tfo->write_pending(cmd); -} - /* transport_generic_write_pending(): * * @@ -4085,22 +4078,16 @@ static int transport_write_pending_qf(st static int transport_generic_write_pending(struct se_cmd *cmd) { unsigned long flags; + bool queue_full_retry = false; int ret; spin_lock_irqsave(&cmd->t_state_lock, flags); cmd->t_state = TRANSPORT_WRITE_PENDING; - spin_unlock_irqrestore(&cmd->t_state_lock, flags); - - if (cmd->transport_qf_callback) { - ret = cmd->transport_qf_callback(cmd); - if (ret == -EAGAIN) - goto queue_full; - else if (ret < 0) - return ret; - - cmd->transport_qf_callback = NULL; - return 0; + if (cmd->se_cmd_flags & SCF_QUEUE_FULL) { + cmd->se_cmd_flags &= SCF_QUEUE_FULL; + queue_full_retry = true; } + spin_unlock_irqrestore(&cmd->t_state_lock, flags); /* * Clear the se_cmd for WRITE_PENDING status in order to set @@ -4109,7 +4096,8 @@ static int transport_generic_write_pendi * to be called with transport_off=1 before the cmd->se_tfo->write_pending * because the se_cmd->se_lun pointer is not being cleared. */ - transport_cmd_check_stop(cmd, 1, 0); + if (!queue_full_retry) + transport_cmd_check_stop(cmd, 1, 0); /* * Call the fabric write_pending function here to let the @@ -4126,8 +4114,7 @@ static int transport_generic_write_pendi queue_full: pr_debug("Handling write_pending QUEUE__FULL: se_cmd: %p\n", cmd); cmd->t_state = TRANSPORT_COMPLETE_QF_WP; - transport_handle_queue_full(cmd, cmd->se_dev, - transport_write_pending_qf); + transport_handle_queue_full(cmd); return ret; } Index: lio-core/include/target/target_core_base.h =================================================================== --- lio-core.orig/include/target/target_core_base.h 2011-10-12 17:05:49.549271375 +0200 +++ lio-core/include/target/target_core_base.h 2011-10-12 17:05:52.498271150 +0200 @@ -123,7 +123,7 @@ enum se_cmd_flags_table { SCF_SENT_DELAYED_TAS = 0x00020000, SCF_ALUA_NON_OPTIMIZED = 0x00040000, SCF_DELAYED_CMD_FROM_SAM_ATTR = 0x00080000, - SCF_UNUSED = 0x00100000, + SCF_QUEUE_FULL = 0x00100000, SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC = 0x00400000, SCF_EMULATE_CDB_ASYNC = 0x01000000, }; @@ -469,7 +469,6 @@ struct se_cmd { struct target_core_fabric_ops *se_tfo; int (*transport_emulate_cdb)(struct se_cmd *); void (*transport_complete_callback)(struct se_cmd *); - int (*transport_qf_callback)(struct se_cmd *); unsigned char *t_task_cdb; unsigned char __t_task_cdb[TCM_MAX_COMMAND_SIZE]; -- 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