Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

scsi: target: Move sess cmd counter to new struct

iSCSI needs to wait on outstanding commands like how SRP and the FC/FCoE
drivers do. It can't use target_stop_session() because for MCS support we
can't stop the entire session during recovery because if other connections
are OK then we want to be able to continue to execute I/O on them.

Move the per session cmd counters to a new struct so iSCSI can allocate
them per connection. The xcopy code can also just not allocate in the
future since it doesn't need to track commands.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Link: https://lore.kernel.org/r/20230319015620.96006-2-michael.christie@oracle.com
Reviewed-by: Maurizio Lombardi <mlombard@redhat.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Mike Christie and committed by
Martin K. Petersen
becd9be6 fe15c26e

+107 -44
+1 -1
drivers/target/target_core_tpg.c
··· 328 328 restart: 329 329 spin_lock_irqsave(&acl->nacl_sess_lock, flags); 330 330 list_for_each_entry(sess, &acl->acl_sess_list, sess_acl_list) { 331 - if (atomic_read(&sess->stopped)) 331 + if (sess->cmd_cnt && atomic_read(&sess->cmd_cnt->stopped)) 332 332 continue; 333 333 334 334 list_del_init(&sess->sess_acl_list);
+96 -39
drivers/target/target_core_transport.c
··· 220 220 sub_api_initialized = 1; 221 221 } 222 222 223 - static void target_release_sess_cmd_refcnt(struct percpu_ref *ref) 223 + static void target_release_cmd_refcnt(struct percpu_ref *ref) 224 224 { 225 - struct se_session *sess = container_of(ref, typeof(*sess), cmd_count); 225 + struct target_cmd_counter *cmd_cnt = container_of(ref, 226 + typeof(*cmd_cnt), 227 + refcnt); 228 + wake_up(&cmd_cnt->refcnt_wq); 229 + } 226 230 227 - wake_up(&sess->cmd_count_wq); 231 + static struct target_cmd_counter *target_alloc_cmd_counter(void) 232 + { 233 + struct target_cmd_counter *cmd_cnt; 234 + int rc; 235 + 236 + cmd_cnt = kzalloc(sizeof(*cmd_cnt), GFP_KERNEL); 237 + if (!cmd_cnt) 238 + return NULL; 239 + 240 + init_completion(&cmd_cnt->stop_done); 241 + init_waitqueue_head(&cmd_cnt->refcnt_wq); 242 + atomic_set(&cmd_cnt->stopped, 0); 243 + 244 + rc = percpu_ref_init(&cmd_cnt->refcnt, target_release_cmd_refcnt, 0, 245 + GFP_KERNEL); 246 + if (rc) 247 + goto free_cmd_cnt; 248 + 249 + return cmd_cnt; 250 + 251 + free_cmd_cnt: 252 + kfree(cmd_cnt); 253 + return NULL; 254 + } 255 + 256 + static void target_free_cmd_counter(struct target_cmd_counter *cmd_cnt) 257 + { 258 + /* 259 + * Drivers like loop do not call target_stop_session during session 260 + * shutdown so we have to drop the ref taken at init time here. 261 + */ 262 + if (!atomic_read(&cmd_cnt->stopped)) 263 + percpu_ref_put(&cmd_cnt->refcnt); 264 + 265 + percpu_ref_exit(&cmd_cnt->refcnt); 228 266 } 229 267 230 268 /** ··· 276 238 INIT_LIST_HEAD(&se_sess->sess_list); 277 239 INIT_LIST_HEAD(&se_sess->sess_acl_list); 278 240 spin_lock_init(&se_sess->sess_cmd_lock); 279 - init_waitqueue_head(&se_sess->cmd_count_wq); 280 - init_completion(&se_sess->stop_done); 281 - atomic_set(&se_sess->stopped, 0); 282 - return percpu_ref_init(&se_sess->cmd_count, 283 - target_release_sess_cmd_refcnt, 0, GFP_KERNEL); 241 + se_sess->cmd_cnt = target_alloc_cmd_counter(); 242 + if (!se_sess->cmd_cnt) 243 + return -ENOMEM; 244 + 245 + return 0; 284 246 } 285 247 EXPORT_SYMBOL(transport_init_session); 286 248 287 249 void transport_uninit_session(struct se_session *se_sess) 288 250 { 289 - /* 290 - * Drivers like iscsi and loop do not call target_stop_session 291 - * during session shutdown so we have to drop the ref taken at init 292 - * time here. 293 - */ 294 - if (!atomic_read(&se_sess->stopped)) 295 - percpu_ref_put(&se_sess->cmd_count); 296 - 297 - percpu_ref_exit(&se_sess->cmd_count); 251 + target_free_cmd_counter(se_sess->cmd_cnt); 298 252 } 299 253 300 254 /** ··· 3000 2970 se_cmd->se_cmd_flags |= SCF_ACK_KREF; 3001 2971 } 3002 2972 3003 - if (!percpu_ref_tryget_live(&se_sess->cmd_count)) 3004 - ret = -ESHUTDOWN; 3005 - 2973 + /* 2974 + * Users like xcopy do not use counters since they never do a stop 2975 + * and wait. 2976 + */ 2977 + if (se_sess->cmd_cnt) { 2978 + if (!percpu_ref_tryget_live(&se_sess->cmd_cnt->refcnt)) 2979 + ret = -ESHUTDOWN; 2980 + else 2981 + se_cmd->cmd_cnt = se_sess->cmd_cnt; 2982 + } 3006 2983 if (ret && ack_kref) 3007 2984 target_put_sess_cmd(se_cmd); 3008 2985 ··· 3030 2993 static void target_release_cmd_kref(struct kref *kref) 3031 2994 { 3032 2995 struct se_cmd *se_cmd = container_of(kref, struct se_cmd, cmd_kref); 3033 - struct se_session *se_sess = se_cmd->se_sess; 2996 + struct target_cmd_counter *cmd_cnt = se_cmd->cmd_cnt; 3034 2997 struct completion *free_compl = se_cmd->free_compl; 3035 2998 struct completion *abrt_compl = se_cmd->abrt_compl; 3036 2999 ··· 3041 3004 if (abrt_compl) 3042 3005 complete(abrt_compl); 3043 3006 3044 - percpu_ref_put(&se_sess->cmd_count); 3007 + if (cmd_cnt) 3008 + percpu_ref_put(&cmd_cnt->refcnt); 3045 3009 } 3046 3010 3047 3011 /** ··· 3161 3123 } 3162 3124 EXPORT_SYMBOL(target_show_cmd); 3163 3125 3164 - static void target_stop_session_confirm(struct percpu_ref *ref) 3126 + static void target_stop_cmd_counter_confirm(struct percpu_ref *ref) 3165 3127 { 3166 - struct se_session *se_sess = container_of(ref, struct se_session, 3167 - cmd_count); 3168 - complete_all(&se_sess->stop_done); 3128 + struct target_cmd_counter *cmd_cnt = container_of(ref, 3129 + struct target_cmd_counter, 3130 + refcnt); 3131 + complete_all(&cmd_cnt->stop_done); 3132 + } 3133 + 3134 + /** 3135 + * target_stop_cmd_counter - Stop new IO from being added to the counter. 3136 + * @cmd_cnt: counter to stop 3137 + */ 3138 + static void target_stop_cmd_counter(struct target_cmd_counter *cmd_cnt) 3139 + { 3140 + pr_debug("Stopping command counter.\n"); 3141 + if (!atomic_cmpxchg(&cmd_cnt->stopped, 0, 1)) 3142 + percpu_ref_kill_and_confirm(&cmd_cnt->refcnt, 3143 + target_stop_cmd_counter_confirm); 3169 3144 } 3170 3145 3171 3146 /** 3172 3147 * target_stop_session - Stop new IO from being queued on the session. 3173 - * @se_sess: session to stop 3148 + * @se_sess: session to stop 3174 3149 */ 3175 3150 void target_stop_session(struct se_session *se_sess) 3176 3151 { 3177 - pr_debug("Stopping session queue.\n"); 3178 - if (atomic_cmpxchg(&se_sess->stopped, 0, 1) == 0) 3179 - percpu_ref_kill_and_confirm(&se_sess->cmd_count, 3180 - target_stop_session_confirm); 3152 + target_stop_cmd_counter(se_sess->cmd_cnt); 3181 3153 } 3182 3154 EXPORT_SYMBOL(target_stop_session); 3183 3155 3184 3156 /** 3185 - * target_wait_for_sess_cmds - Wait for outstanding commands 3186 - * @se_sess: session to wait for active I/O 3157 + * target_wait_for_cmds - Wait for outstanding cmds. 3158 + * @cmd_cnt: counter to wait for active I/O for. 3187 3159 */ 3188 - void target_wait_for_sess_cmds(struct se_session *se_sess) 3160 + static void target_wait_for_cmds(struct target_cmd_counter *cmd_cnt) 3189 3161 { 3190 3162 int ret; 3191 3163 3192 - WARN_ON_ONCE(!atomic_read(&se_sess->stopped)); 3164 + WARN_ON_ONCE(!atomic_read(&cmd_cnt->stopped)); 3193 3165 3194 3166 do { 3195 3167 pr_debug("Waiting for running cmds to complete.\n"); 3196 - ret = wait_event_timeout(se_sess->cmd_count_wq, 3197 - percpu_ref_is_zero(&se_sess->cmd_count), 3198 - 180 * HZ); 3168 + ret = wait_event_timeout(cmd_cnt->refcnt_wq, 3169 + percpu_ref_is_zero(&cmd_cnt->refcnt), 3170 + 180 * HZ); 3199 3171 } while (ret <= 0); 3200 3172 3201 - wait_for_completion(&se_sess->stop_done); 3173 + wait_for_completion(&cmd_cnt->stop_done); 3202 3174 pr_debug("Waiting for cmds done.\n"); 3175 + } 3176 + 3177 + /** 3178 + * target_wait_for_sess_cmds - Wait for outstanding commands 3179 + * @se_sess: session to wait for active I/O 3180 + */ 3181 + void target_wait_for_sess_cmds(struct se_session *se_sess) 3182 + { 3183 + target_wait_for_cmds(se_sess->cmd_cnt); 3203 3184 } 3204 3185 EXPORT_SYMBOL(target_wait_for_sess_cmds); 3205 3186
+1
include/target/iscsi/iscsi_target_core.h
··· 600 600 struct iscsi_tpg_np *tpg_np; 601 601 /* Pointer to parent session */ 602 602 struct iscsit_session *sess; 603 + struct target_cmd_counter *cmd_cnt; 603 604 int bitmap_id; 604 605 int rx_thread_active; 605 606 struct task_struct *rx_thread;
+9 -4
include/target/target_core_base.h
··· 494 494 struct se_lun *se_lun; 495 495 /* Only used for internal passthrough and legacy TCM fabric modules */ 496 496 struct se_session *se_sess; 497 + struct target_cmd_counter *cmd_cnt; 497 498 struct se_tmr_req *se_tmr_req; 498 499 struct llist_node se_cmd_list; 499 500 struct completion *free_compl; ··· 620 619 acl_fabric_stat_group); 621 620 } 622 621 623 - struct se_session { 622 + struct target_cmd_counter { 623 + struct percpu_ref refcnt; 624 + wait_queue_head_t refcnt_wq; 625 + struct completion stop_done; 624 626 atomic_t stopped; 627 + }; 628 + 629 + struct se_session { 625 630 u64 sess_bin_isid; 626 631 enum target_prot_op sup_prot_ops; 627 632 enum target_prot_type sess_prot_type; 628 633 struct se_node_acl *se_node_acl; 629 634 struct se_portal_group *se_tpg; 630 635 void *fabric_sess_ptr; 631 - struct percpu_ref cmd_count; 632 636 struct list_head sess_list; 633 637 struct list_head sess_acl_list; 634 638 spinlock_t sess_cmd_lock; 635 - wait_queue_head_t cmd_count_wq; 636 - struct completion stop_done; 637 639 void *sess_cmd_map; 638 640 struct sbitmap_queue sess_tag_pool; 641 + struct target_cmd_counter *cmd_cnt; 639 642 }; 640 643 641 644 struct se_device;