diff options
| author | Christoph Hellwig <hch@infradead.org> | 2011-10-17 13:56:53 -0400 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2011-10-23 23:21:52 -0400 |
| commit | 35e0e757537b9239172e35db773dd062727fd612 (patch) | |
| tree | 3a54e1e426f1a962219325eac474b715a4699924 /drivers | |
| parent | 59aaad1ec44d9a77c32b873b001f31c5af47fcc7 (diff) | |
target: use a workqueue for I/O completions
Instead of abusing the target processing thread for offloading I/O
completion in the backends to user context add a new workqueue. This means
completions can be processed as fast as available CPU time allows it,
including in parallel with other completions and more importantly I/O
submission or QUEUE FULL retries. This should give much better performance
especially on loaded systems.
As a fallout we can merge all the completed states into a single
one.
On the downside this change complicates lun reset handling a bit by
requiring us to cancel a work item only for those states that have it
initialized. The alternative would be to either always initialize the work
item to a dummy handler, or always use the same handler and do a switch on
the state. The long term solution will be a flag that says that the command
has an initialized work item, but that's only going to be useful once we
have more users.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/target/target_core_tmr.c | 10 | ||||
| -rw-r--r-- | drivers/target/target_core_transport.c | 165 |
2 files changed, 95 insertions, 80 deletions
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 532ce317406a..570b144a1edb 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
| @@ -255,6 +255,16 @@ static void core_tmr_drain_task_list( | |||
| 255 | atomic_read(&cmd->t_transport_stop), | 255 | atomic_read(&cmd->t_transport_stop), |
| 256 | atomic_read(&cmd->t_transport_sent)); | 256 | atomic_read(&cmd->t_transport_sent)); |
| 257 | 257 | ||
| 258 | /* | ||
| 259 | * If the command may be queued onto a workqueue cancel it now. | ||
| 260 | * | ||
| 261 | * This is equivalent to removal from the execute queue in the | ||
| 262 | * loop above, but we do it down here given that | ||
| 263 | * cancel_work_sync may block. | ||
| 264 | */ | ||
| 265 | if (cmd->t_state == TRANSPORT_COMPLETE) | ||
| 266 | cancel_work_sync(&cmd->work); | ||
| 267 | |||
| 258 | spin_lock_irqsave(&cmd->t_state_lock, flags); | 268 | spin_lock_irqsave(&cmd->t_state_lock, flags); |
| 259 | target_stop_task(task, &flags); | 269 | target_stop_task(task, &flags); |
| 260 | 270 | ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 87beae6c76a0..774ff00b1110 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -58,6 +58,7 @@ | |||
| 58 | 58 | ||
| 59 | static int sub_api_initialized; | 59 | static int sub_api_initialized; |
| 60 | 60 | ||
| 61 | static struct workqueue_struct *target_completion_wq; | ||
| 61 | static struct kmem_cache *se_cmd_cache; | 62 | static struct kmem_cache *se_cmd_cache; |
| 62 | static struct kmem_cache *se_sess_cache; | 63 | static struct kmem_cache *se_sess_cache; |
| 63 | struct kmem_cache *se_tmr_req_cache; | 64 | struct kmem_cache *se_tmr_req_cache; |
| @@ -84,6 +85,8 @@ static int transport_generic_get_mem(struct se_cmd *cmd); | |||
| 84 | static void transport_put_cmd(struct se_cmd *cmd); | 85 | static void transport_put_cmd(struct se_cmd *cmd); |
| 85 | static void transport_remove_cmd_from_queue(struct se_cmd *cmd); | 86 | static void transport_remove_cmd_from_queue(struct se_cmd *cmd); |
| 86 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); | 87 | static int transport_set_sense_codes(struct se_cmd *cmd, u8 asc, u8 ascq); |
| 88 | static void transport_generic_request_failure(struct se_cmd *, int, int); | ||
| 89 | static void target_complete_ok_work(struct work_struct *work); | ||
| 87 | 90 | ||
| 88 | int init_se_kmem_caches(void) | 91 | int init_se_kmem_caches(void) |
| 89 | { | 92 | { |
| @@ -99,7 +102,7 @@ int init_se_kmem_caches(void) | |||
| 99 | if (!se_tmr_req_cache) { | 102 | if (!se_tmr_req_cache) { |
| 100 | pr_err("kmem_cache_create() for struct se_tmr_req" | 103 | pr_err("kmem_cache_create() for struct se_tmr_req" |
| 101 | " failed\n"); | 104 | " failed\n"); |
| 102 | goto out; | 105 | goto out_free_cmd_cache; |
| 103 | } | 106 | } |
| 104 | se_sess_cache = kmem_cache_create("se_sess_cache", | 107 | se_sess_cache = kmem_cache_create("se_sess_cache", |
| 105 | sizeof(struct se_session), __alignof__(struct se_session), | 108 | sizeof(struct se_session), __alignof__(struct se_session), |
| @@ -107,14 +110,14 @@ int init_se_kmem_caches(void) | |||
| 107 | if (!se_sess_cache) { | 110 | if (!se_sess_cache) { |
| 108 | pr_err("kmem_cache_create() for struct se_session" | 111 | pr_err("kmem_cache_create() for struct se_session" |
| 109 | " failed\n"); | 112 | " failed\n"); |
| 110 | goto out; | 113 | goto out_free_tmr_req_cache; |
| 111 | } | 114 | } |
| 112 | se_ua_cache = kmem_cache_create("se_ua_cache", | 115 | se_ua_cache = kmem_cache_create("se_ua_cache", |
| 113 | sizeof(struct se_ua), __alignof__(struct se_ua), | 116 | sizeof(struct se_ua), __alignof__(struct se_ua), |
| 114 | 0, NULL); | 117 | 0, NULL); |
| 115 | if (!se_ua_cache) { | 118 | if (!se_ua_cache) { |
| 116 | pr_err("kmem_cache_create() for struct se_ua failed\n"); | 119 | pr_err("kmem_cache_create() for struct se_ua failed\n"); |
| 117 | goto out; | 120 | goto out_free_sess_cache; |
| 118 | } | 121 | } |
| 119 | t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache", | 122 | t10_pr_reg_cache = kmem_cache_create("t10_pr_reg_cache", |
| 120 | sizeof(struct t10_pr_registration), | 123 | sizeof(struct t10_pr_registration), |
| @@ -122,7 +125,7 @@ int init_se_kmem_caches(void) | |||
| 122 | if (!t10_pr_reg_cache) { | 125 | if (!t10_pr_reg_cache) { |
| 123 | pr_err("kmem_cache_create() for struct t10_pr_registration" | 126 | pr_err("kmem_cache_create() for struct t10_pr_registration" |
| 124 | " failed\n"); | 127 | " failed\n"); |
| 125 | goto out; | 128 | goto out_free_ua_cache; |
| 126 | } | 129 | } |
| 127 | t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache", | 130 | t10_alua_lu_gp_cache = kmem_cache_create("t10_alua_lu_gp_cache", |
| 128 | sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp), | 131 | sizeof(struct t10_alua_lu_gp), __alignof__(struct t10_alua_lu_gp), |
| @@ -130,7 +133,7 @@ int init_se_kmem_caches(void) | |||
| 130 | if (!t10_alua_lu_gp_cache) { | 133 | if (!t10_alua_lu_gp_cache) { |
| 131 | pr_err("kmem_cache_create() for t10_alua_lu_gp_cache" | 134 | pr_err("kmem_cache_create() for t10_alua_lu_gp_cache" |
| 132 | " failed\n"); | 135 | " failed\n"); |
| 133 | goto out; | 136 | goto out_free_pr_reg_cache; |
| 134 | } | 137 | } |
| 135 | t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache", | 138 | t10_alua_lu_gp_mem_cache = kmem_cache_create("t10_alua_lu_gp_mem_cache", |
| 136 | sizeof(struct t10_alua_lu_gp_member), | 139 | sizeof(struct t10_alua_lu_gp_member), |
| @@ -138,7 +141,7 @@ int init_se_kmem_caches(void) | |||
| 138 | if (!t10_alua_lu_gp_mem_cache) { | 141 | if (!t10_alua_lu_gp_mem_cache) { |
| 139 | pr_err("kmem_cache_create() for t10_alua_lu_gp_mem_" | 142 | pr_err("kmem_cache_create() for t10_alua_lu_gp_mem_" |
| 140 | "cache failed\n"); | 143 | "cache failed\n"); |
| 141 | goto out; | 144 | goto out_free_lu_gp_cache; |
| 142 | } | 145 | } |
| 143 | t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache", | 146 | t10_alua_tg_pt_gp_cache = kmem_cache_create("t10_alua_tg_pt_gp_cache", |
| 144 | sizeof(struct t10_alua_tg_pt_gp), | 147 | sizeof(struct t10_alua_tg_pt_gp), |
| @@ -146,7 +149,7 @@ int init_se_kmem_caches(void) | |||
| 146 | if (!t10_alua_tg_pt_gp_cache) { | 149 | if (!t10_alua_tg_pt_gp_cache) { |
| 147 | pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" | 150 | pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" |
| 148 | "cache failed\n"); | 151 | "cache failed\n"); |
| 149 | goto out; | 152 | goto out_free_lu_gp_mem_cache; |
| 150 | } | 153 | } |
| 151 | t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( | 154 | t10_alua_tg_pt_gp_mem_cache = kmem_cache_create( |
| 152 | "t10_alua_tg_pt_gp_mem_cache", | 155 | "t10_alua_tg_pt_gp_mem_cache", |
| @@ -156,34 +159,41 @@ int init_se_kmem_caches(void) | |||
| 156 | if (!t10_alua_tg_pt_gp_mem_cache) { | 159 | if (!t10_alua_tg_pt_gp_mem_cache) { |
| 157 | pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" | 160 | pr_err("kmem_cache_create() for t10_alua_tg_pt_gp_" |
| 158 | "mem_t failed\n"); | 161 | "mem_t failed\n"); |
| 159 | goto out; | 162 | goto out_free_tg_pt_gp_cache; |
| 160 | } | 163 | } |
| 161 | 164 | ||
| 165 | target_completion_wq = alloc_workqueue("target_completion", | ||
| 166 | WQ_MEM_RECLAIM, 0); | ||
| 167 | if (!target_completion_wq) | ||
| 168 | goto out_free_tg_pt_gp_mem_cache; | ||
| 169 | |||
| 162 | return 0; | 170 | return 0; |
| 171 | |||
| 172 | out_free_tg_pt_gp_mem_cache: | ||
| 173 | kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); | ||
| 174 | out_free_tg_pt_gp_cache: | ||
| 175 | kmem_cache_destroy(t10_alua_tg_pt_gp_cache); | ||
| 176 | out_free_lu_gp_mem_cache: | ||
| 177 | kmem_cache_destroy(t10_alua_lu_gp_mem_cache); | ||
| 178 | out_free_lu_gp_cache: | ||
| 179 | kmem_cache_destroy(t10_alua_lu_gp_cache); | ||
| 180 | out_free_pr_reg_cache: | ||
| 181 | kmem_cache_destroy(t10_pr_reg_cache); | ||
| 182 | out_free_ua_cache: | ||
| 183 | kmem_cache_destroy(se_ua_cache); | ||
| 184 | out_free_sess_cache: | ||
| 185 | kmem_cache_destroy(se_sess_cache); | ||
| 186 | out_free_tmr_req_cache: | ||
| 187 | kmem_cache_destroy(se_tmr_req_cache); | ||
| 188 | out_free_cmd_cache: | ||
| 189 | kmem_cache_destroy(se_cmd_cache); | ||
| 163 | out: | 190 | out: |
| 164 | if (se_cmd_cache) | ||
| 165 | kmem_cache_destroy(se_cmd_cache); | ||
| 166 | if (se_tmr_req_cache) | ||
| 167 | kmem_cache_destroy(se_tmr_req_cache); | ||
| 168 | if (se_sess_cache) | ||
| 169 | kmem_cache_destroy(se_sess_cache); | ||
| 170 | if (se_ua_cache) | ||
| 171 | kmem_cache_destroy(se_ua_cache); | ||
| 172 | if (t10_pr_reg_cache) | ||
| 173 | kmem_cache_destroy(t10_pr_reg_cache); | ||
| 174 | if (t10_alua_lu_gp_cache) | ||
| 175 | kmem_cache_destroy(t10_alua_lu_gp_cache); | ||
| 176 | if (t10_alua_lu_gp_mem_cache) | ||
| 177 | kmem_cache_destroy(t10_alua_lu_gp_mem_cache); | ||
| 178 | if (t10_alua_tg_pt_gp_cache) | ||
| 179 | kmem_cache_destroy(t10_alua_tg_pt_gp_cache); | ||
| 180 | if (t10_alua_tg_pt_gp_mem_cache) | ||
| 181 | kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache); | ||
| 182 | return -ENOMEM; | 191 | return -ENOMEM; |
| 183 | } | 192 | } |
| 184 | 193 | ||
| 185 | void release_se_kmem_caches(void) | 194 | void release_se_kmem_caches(void) |
| 186 | { | 195 | { |
| 196 | destroy_workqueue(target_completion_wq); | ||
| 187 | kmem_cache_destroy(se_cmd_cache); | 197 | kmem_cache_destroy(se_cmd_cache); |
| 188 | kmem_cache_destroy(se_tmr_req_cache); | 198 | kmem_cache_destroy(se_tmr_req_cache); |
| 189 | kmem_cache_destroy(se_sess_cache); | 199 | kmem_cache_destroy(se_sess_cache); |
| @@ -689,6 +699,33 @@ void transport_complete_sync_cache(struct se_cmd *cmd, int good) | |||
| 689 | } | 699 | } |
| 690 | EXPORT_SYMBOL(transport_complete_sync_cache); | 700 | EXPORT_SYMBOL(transport_complete_sync_cache); |
| 691 | 701 | ||
| 702 | static void target_complete_timeout_work(struct work_struct *work) | ||
| 703 | { | ||
| 704 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); | ||
| 705 | unsigned long flags; | ||
| 706 | |||
| 707 | /* | ||
| 708 | * Reset cmd->t_se_count to allow transport_put_cmd() | ||
| 709 | * to allow last call to free memory resources. | ||
| 710 | */ | ||
| 711 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
| 712 | if (atomic_read(&cmd->t_transport_timeout) > 1) { | ||
| 713 | int tmp = (atomic_read(&cmd->t_transport_timeout) - 1); | ||
| 714 | |||
| 715 | atomic_sub(tmp, &cmd->t_se_count); | ||
| 716 | } | ||
| 717 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 718 | |||
| 719 | transport_put_cmd(cmd); | ||
| 720 | } | ||
| 721 | |||
| 722 | static void target_complete_failure_work(struct work_struct *work) | ||
| 723 | { | ||
| 724 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); | ||
| 725 | |||
| 726 | transport_generic_request_failure(cmd, 1, 1); | ||
| 727 | } | ||
| 728 | |||
| 692 | /* transport_complete_task(): | 729 | /* transport_complete_task(): |
| 693 | * | 730 | * |
| 694 | * Called from interrupt and non interrupt context depending | 731 | * Called from interrupt and non interrupt context depending |
| @@ -698,7 +735,6 @@ void transport_complete_task(struct se_task *task, int success) | |||
| 698 | { | 735 | { |
| 699 | struct se_cmd *cmd = task->task_se_cmd; | 736 | struct se_cmd *cmd = task->task_se_cmd; |
| 700 | struct se_device *dev = cmd->se_dev; | 737 | struct se_device *dev = cmd->se_dev; |
| 701 | int t_state; | ||
| 702 | unsigned long flags; | 738 | unsigned long flags; |
| 703 | #if 0 | 739 | #if 0 |
| 704 | pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task, | 740 | pr_debug("task: %p CDB: 0x%02x obj_ptr: %p\n", task, |
| @@ -749,17 +785,12 @@ void transport_complete_task(struct se_task *task, int success) | |||
| 749 | * the processing thread. | 785 | * the processing thread. |
| 750 | */ | 786 | */ |
| 751 | if (task->task_flags & TF_TIMEOUT) { | 787 | if (task->task_flags & TF_TIMEOUT) { |
| 752 | if (!atomic_dec_and_test( | 788 | if (!atomic_dec_and_test(&cmd->t_task_cdbs_timeout_left)) { |
| 753 | &cmd->t_task_cdbs_timeout_left)) { | 789 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 754 | spin_unlock_irqrestore(&cmd->t_state_lock, | ||
| 755 | flags); | ||
| 756 | return; | 790 | return; |
| 757 | } | 791 | } |
| 758 | t_state = TRANSPORT_COMPLETE_TIMEOUT; | 792 | INIT_WORK(&cmd->work, target_complete_timeout_work); |
| 759 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 793 | goto out_queue; |
| 760 | |||
| 761 | transport_add_cmd_to_queue(cmd, t_state, false); | ||
| 762 | return; | ||
| 763 | } | 794 | } |
| 764 | atomic_dec(&cmd->t_task_cdbs_timeout_left); | 795 | atomic_dec(&cmd->t_task_cdbs_timeout_left); |
| 765 | 796 | ||
| @@ -769,28 +800,29 @@ void transport_complete_task(struct se_task *task, int success) | |||
| 769 | * device queue depending upon int success. | 800 | * device queue depending upon int success. |
| 770 | */ | 801 | */ |
| 771 | if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) { | 802 | if (!atomic_dec_and_test(&cmd->t_task_cdbs_left)) { |
| 772 | if (!success) | ||
| 773 | cmd->t_tasks_failed = 1; | ||
| 774 | |||
| 775 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 803 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 776 | return; | 804 | return; |
| 777 | } | 805 | } |
| 778 | 806 | ||
| 779 | if (!success || cmd->t_tasks_failed) { | 807 | if (!success || cmd->t_tasks_failed) { |
| 780 | t_state = TRANSPORT_COMPLETE_FAILURE; | ||
| 781 | if (!task->task_error_status) { | 808 | if (!task->task_error_status) { |
| 782 | task->task_error_status = | 809 | task->task_error_status = |
| 783 | PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 810 | PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
| 784 | cmd->transport_error_status = | 811 | cmd->transport_error_status = |
| 785 | PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; | 812 | PYX_TRANSPORT_UNKNOWN_SAM_OPCODE; |
| 786 | } | 813 | } |
| 814 | INIT_WORK(&cmd->work, target_complete_failure_work); | ||
| 787 | } else { | 815 | } else { |
| 788 | atomic_set(&cmd->t_transport_complete, 1); | 816 | atomic_set(&cmd->t_transport_complete, 1); |
| 789 | t_state = TRANSPORT_COMPLETE_OK; | 817 | INIT_WORK(&cmd->work, target_complete_ok_work); |
| 790 | } | 818 | } |
| 819 | |||
| 820 | out_queue: | ||
| 821 | cmd->t_state = TRANSPORT_COMPLETE; | ||
| 822 | atomic_set(&cmd->t_transport_active, 1); | ||
| 791 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 823 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 792 | 824 | ||
| 793 | transport_add_cmd_to_queue(cmd, t_state, false); | 825 | queue_work(target_completion_wq, &cmd->work); |
| 794 | } | 826 | } |
| 795 | EXPORT_SYMBOL(transport_complete_task); | 827 | EXPORT_SYMBOL(transport_complete_task); |
| 796 | 828 | ||
| @@ -1642,8 +1674,6 @@ int transport_generic_allocate_tasks( | |||
| 1642 | } | 1674 | } |
| 1643 | EXPORT_SYMBOL(transport_generic_allocate_tasks); | 1675 | EXPORT_SYMBOL(transport_generic_allocate_tasks); |
| 1644 | 1676 | ||
| 1645 | static void transport_generic_request_failure(struct se_cmd *, int, int); | ||
| 1646 | |||
| 1647 | /* | 1677 | /* |
| 1648 | * Used by fabric module frontends to queue tasks directly. | 1678 | * Used by fabric module frontends to queue tasks directly. |
| 1649 | * Many only be used from process context only | 1679 | * Many only be used from process context only |
| @@ -1985,25 +2015,6 @@ static void transport_direct_request_timeout(struct se_cmd *cmd) | |||
| 1985 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2015 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 1986 | } | 2016 | } |
| 1987 | 2017 | ||
| 1988 | static void transport_generic_request_timeout(struct se_cmd *cmd) | ||
| 1989 | { | ||
| 1990 | unsigned long flags; | ||
| 1991 | |||
| 1992 | /* | ||
| 1993 | * Reset cmd->t_se_count to allow transport_put_cmd() | ||
| 1994 | * to allow last call to free memory resources. | ||
| 1995 | */ | ||
| 1996 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
| 1997 | if (atomic_read(&cmd->t_transport_timeout) > 1) { | ||
| 1998 | int tmp = (atomic_read(&cmd->t_transport_timeout) - 1); | ||
| 1999 | |||
| 2000 | atomic_sub(tmp, &cmd->t_se_count); | ||
| 2001 | } | ||
| 2002 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 2003 | |||
| 2004 | transport_put_cmd(cmd); | ||
| 2005 | } | ||
| 2006 | |||
| 2007 | static inline u32 transport_lba_21(unsigned char *cdb) | 2018 | static inline u32 transport_lba_21(unsigned char *cdb) |
| 2008 | { | 2019 | { |
| 2009 | return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; | 2020 | return ((cdb[1] & 0x1f) << 16) | (cdb[2] << 8) | cdb[3]; |
| @@ -2094,10 +2105,12 @@ static void transport_task_timeout_handler(unsigned long data) | |||
| 2094 | pr_debug("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n", | 2105 | pr_debug("transport task: %p cmd: %p timeout ZERO t_task_cdbs_left\n", |
| 2095 | task, cmd); | 2106 | task, cmd); |
| 2096 | 2107 | ||
| 2097 | cmd->t_state = TRANSPORT_COMPLETE_FAILURE; | 2108 | INIT_WORK(&cmd->work, target_complete_failure_work); |
| 2109 | cmd->t_state = TRANSPORT_COMPLETE; | ||
| 2110 | atomic_set(&cmd->t_transport_active, 1); | ||
| 2098 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 2111 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 2099 | 2112 | ||
| 2100 | transport_add_cmd_to_queue(cmd, TRANSPORT_COMPLETE_FAILURE, false); | 2113 | queue_work(target_completion_wq, &cmd->work); |
| 2101 | } | 2114 | } |
| 2102 | 2115 | ||
| 2103 | static void transport_start_task_timer(struct se_task *task) | 2116 | static void transport_start_task_timer(struct se_task *task) |
| @@ -2879,7 +2892,7 @@ static int transport_generic_cmd_sequencer( | |||
| 2879 | if (passthrough) | 2892 | if (passthrough) |
| 2880 | break; | 2893 | break; |
| 2881 | /* | 2894 | /* |
| 2882 | * Setup BIDI XOR callback to be run during transport_generic_complete_ok() | 2895 | * Setup BIDI XOR callback to be run after I/O completion. |
| 2883 | */ | 2896 | */ |
| 2884 | cmd->transport_complete_callback = &transport_xor_callback; | 2897 | cmd->transport_complete_callback = &transport_xor_callback; |
| 2885 | cmd->t_tasks_fua = (cdb[1] & 0x8); | 2898 | cmd->t_tasks_fua = (cdb[1] & 0x8); |
| @@ -2913,8 +2926,8 @@ static int transport_generic_cmd_sequencer( | |||
| 2913 | break; | 2926 | break; |
| 2914 | 2927 | ||
| 2915 | /* | 2928 | /* |
| 2916 | * Setup BIDI XOR callback to be run during | 2929 | * Setup BIDI XOR callback to be run during after I/O |
| 2917 | * transport_generic_complete_ok() | 2930 | * completion. |
| 2918 | */ | 2931 | */ |
| 2919 | cmd->transport_complete_callback = &transport_xor_callback; | 2932 | cmd->transport_complete_callback = &transport_xor_callback; |
| 2920 | cmd->t_tasks_fua = (cdb[10] & 0x8); | 2933 | cmd->t_tasks_fua = (cdb[10] & 0x8); |
| @@ -3311,8 +3324,7 @@ out_invalid_cdb_field: | |||
| 3311 | } | 3324 | } |
| 3312 | 3325 | ||
| 3313 | /* | 3326 | /* |
| 3314 | * Called from transport_generic_complete_ok() and | 3327 | * Called from I/O completion to determine which dormant/delayed |
| 3315 | * transport_generic_request_failure() to determine which dormant/delayed | ||
| 3316 | * and ordered cmds need to have their tasks added to the execution queue. | 3328 | * and ordered cmds need to have their tasks added to the execution queue. |
| 3317 | */ | 3329 | */ |
| 3318 | static void transport_complete_task_attr(struct se_cmd *cmd) | 3330 | static void transport_complete_task_attr(struct se_cmd *cmd) |
| @@ -3433,9 +3445,11 @@ static void transport_handle_queue_full( | |||
| 3433 | schedule_work(&cmd->se_dev->qf_work_queue); | 3445 | schedule_work(&cmd->se_dev->qf_work_queue); |
| 3434 | } | 3446 | } |
| 3435 | 3447 | ||
| 3436 | static void transport_generic_complete_ok(struct se_cmd *cmd) | 3448 | static void target_complete_ok_work(struct work_struct *work) |
| 3437 | { | 3449 | { |
| 3450 | struct se_cmd *cmd = container_of(work, struct se_cmd, work); | ||
| 3438 | int reason = 0, ret; | 3451 | int reason = 0, ret; |
| 3452 | |||
| 3439 | /* | 3453 | /* |
| 3440 | * Check if we need to move delayed/dormant tasks from cmds on the | 3454 | * Check if we need to move delayed/dormant tasks from cmds on the |
| 3441 | * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task | 3455 | * delayed execution list after a HEAD_OF_QUEUE or ORDERED Task |
| @@ -4778,21 +4792,12 @@ get_cmd: | |||
| 4778 | case TRANSPORT_PROCESS_WRITE: | 4792 | case TRANSPORT_PROCESS_WRITE: |
| 4779 | transport_generic_process_write(cmd); | 4793 | transport_generic_process_write(cmd); |
| 4780 | break; | 4794 | break; |
| 4781 | case TRANSPORT_COMPLETE_OK: | ||
| 4782 | transport_generic_complete_ok(cmd); | ||
| 4783 | break; | ||
| 4784 | case TRANSPORT_FREE_CMD_INTR: | 4795 | case TRANSPORT_FREE_CMD_INTR: |
| 4785 | transport_generic_free_cmd(cmd, 0); | 4796 | transport_generic_free_cmd(cmd, 0); |
| 4786 | break; | 4797 | break; |
| 4787 | case TRANSPORT_PROCESS_TMR: | 4798 | case TRANSPORT_PROCESS_TMR: |
| 4788 | transport_generic_do_tmr(cmd); | 4799 | transport_generic_do_tmr(cmd); |
| 4789 | break; | 4800 | break; |
| 4790 | case TRANSPORT_COMPLETE_FAILURE: | ||
| 4791 | transport_generic_request_failure(cmd, 1, 1); | ||
| 4792 | break; | ||
| 4793 | case TRANSPORT_COMPLETE_TIMEOUT: | ||
| 4794 | transport_generic_request_timeout(cmd); | ||
| 4795 | break; | ||
| 4796 | case TRANSPORT_COMPLETE_QF_WP: | 4801 | case TRANSPORT_COMPLETE_QF_WP: |
| 4797 | transport_write_pending_qf(cmd); | 4802 | transport_write_pending_qf(cmd); |
| 4798 | break; | 4803 | break; |
