From: <vl...@us...> - 2007-08-14 16:55:03
|
Revision: 159 http://scst.svn.sourceforge.net/scst/?rev=159&view=rev Author: vlnb Date: 2007-08-14 09:54:54 -0700 (Tue, 14 Aug 2007) Log Message: ----------- - Call of pre_unreg_sess() moved to scst_mgmt_thread, because of scst_mutex deadlock with scst_user's pre_unreg_sess() handler - scst_check_local_events() cleanups - In scst_user notification about aborted commands added, user space interface changed - Other minor fixes and cleanups Modified Paths: -------------- trunk/scst/include/scsi_tgt.h trunk/scst/include/scst_user.h trunk/scst/src/Makefile trunk/scst/src/dev_handlers/scst_disk.c trunk/scst/src/dev_handlers/scst_modisk.c trunk/scst/src/dev_handlers/scst_tape.c trunk/scst/src/dev_handlers/scst_user.c trunk/scst/src/dev_handlers/scst_vdisk.c trunk/scst/src/scst.c trunk/scst/src/scst_lib.c trunk/scst/src/scst_priv.h trunk/scst/src/scst_targ.c Modified: trunk/scst/include/scsi_tgt.h =================================================================== --- trunk/scst/include/scsi_tgt.h 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/include/scsi_tgt.h 2007-08-14 16:54:54 UTC (rev 159) @@ -285,6 +285,19 @@ /* Set if session is initialized and ready */ #define SCST_SESS_IPH_READY 3 +/************************************************************* + ** Session shutdown phases + *************************************************************/ + +/* Set if session is initialized and ready */ +#define SCST_SESS_SPH_READY 0 + +/* Set if session is on calling pre_unreg_sess() phase */ +#define SCST_SESS_SPH_PRE_UNREG 1 + +/* Set if session is shutting down */ +#define SCST_SESS_SPH_SHUTDOWN 2 + /************************************************************* ** Cmd's async (atomic) flags *************************************************************/ @@ -833,20 +846,27 @@ struct scst_session { - /* Initialization phase, one of SCST_SESS_IPH_* constants */ + /* + * Initialization phase, one of SCST_SESS_IPH_* constants, protected by + * sess_list_lock + */ int init_phase; atomic_t refcnt; /* get/put counter */ - /************************************************************* - ** Session's flags. Serialized by scst_mgmt_lock - *************************************************************/ + /**************************************************************/ - /* Set if the session is shutting down */ - unsigned int shutting_down:1; + /* Alive commands for this session. ToDo: make it part of the common IO flow control */ + atomic_t sess_cmd_count; - /**************************************************************/ + spinlock_t sess_list_lock; /* protects search_cmd_list, etc */ + /* + * List of cmds in this session. Used to find a cmd in the + * session. Protected by sess_list_lock. + */ + struct list_head search_cmd_list; + /* * Hash list of tgt_dev's for this session, protected by scst_mutex * and suspended activity @@ -859,22 +879,11 @@ /* List entry for the sessions list inside ACG */ struct list_head acg_sess_list_entry; + struct scst_tgt *tgt; /* corresponding target */ + /* Used for storage of target driver private stuff */ void *tgt_priv; - /* Alive commands for this session. ToDo: make it part of common IO flow control */ - atomic_t sess_cmd_count; - - spinlock_t sess_list_lock; /* protects search_cmd_list, etc */ - - /* - * List of cmds in this session. Used to find a cmd in the - * session. Protected by sess_list_lock. - */ - struct list_head search_cmd_list; - - struct scst_tgt *tgt; /* corresponding target */ - /* Name of attached initiator */ const char *initiator_name; @@ -882,8 +891,11 @@ struct list_head sess_list_entry; /* List entry for the list that keeps session, waiting for the init */ - struct list_head sess_mgmt_list_entry; + struct list_head sess_init_list_entry; + /* List entry for the list that keeps session, waiting for the shutdown */ + struct list_head sess_shut_list_entry; + /* * Lists of deffered during session initialization commands. * Protected by sess_list_lock. @@ -891,12 +903,16 @@ struct list_head init_deferred_cmd_list; struct list_head init_deferred_mcmd_list; + /* + * Shutdown phase, one of SCST_SESS_SPH_* constants, unprotected. + * Async. relating to init_phase, must be a separate variable, because + * session could be unregistered before async. registration is finished. + */ + unsigned long shut_phase; + /* Used if scst_unregister_session() called in wait mode */ struct completion *shutdown_compl; - /* Used to push some unregister_session() works out of IRQ */ - struct work_struct unreg_work; - /* * Functions and data for user callbacks from scst_register_session() * and scst_unregister_session() Modified: trunk/scst/include/scst_user.h =================================================================== --- trunk/scst/include/scst_user.h 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/include/scst_user.h 2007-08-14 16:54:54 UTC (rev 159) @@ -23,7 +23,7 @@ #define DEV_USER_NAME "scst_user" #define DEV_USER_PATH "/dev/" -#define DEV_USER_VERSION 96 +#define DEV_USER_VERSION 961 /* * Chosen so sizeof(scst_user_sess) <= sizeof(scst_user_scsi_cmd_exec) @@ -95,7 +95,7 @@ struct scst_user_dev_desc { - uint8_t version; + uint32_t version; uint8_t type; struct scst_user_opt opt; uint32_t block_size; @@ -168,6 +168,7 @@ aligned_u64 pbuf; int32_t resp_data_len; uint8_t buffer_cached; + uint8_t aborted; uint8_t status; }; Modified: trunk/scst/src/Makefile =================================================================== --- trunk/scst/src/Makefile 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/Makefile 2007-08-14 16:54:54 UTC (rev 159) @@ -81,6 +81,12 @@ install -m 644 Module.symvers $(INSTALL_DIR_H) endif -depmod -a $(KVER) + @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" + @echo "!! Now don't forget to rebuild and reinstall all your !!" + @echo "!! target drivers, custom dev handlers and necessary user !!" + @echo "!! space applications. Otherwise, because of the versions !!" + @echo "!! mismatch, you could have many problems and crashes! !!" + @echo "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" uninstall: cd $(DEV_HANDLERS_DIR) && $(MAKE) $@ Modified: trunk/scst/src/dev_handlers/scst_disk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_disk.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/dev_handlers/scst_disk.c 2007-08-14 16:54:54 UTC (rev 159) @@ -350,13 +350,14 @@ TRACE_ENTRY(); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; + cmd->status = 0; + cmd->msg_status = 0; + cmd->host_status = DID_OK; + cmd->driver_status = 0; + switch (opcode) { case WRITE_6: case WRITE_10: @@ -366,24 +367,16 @@ case READ_10: case READ_12: case READ_16: - goto out_compl; + cmd->completed = 1; + break; } -out: - TRACE_EXIT_RES(res); - return res; - -out_compl: - cmd->completed = 1; - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - -out_uncompl: +out_done: res = SCST_EXEC_COMPLETED; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - goto out; + + TRACE_EXIT_RES(res); + return res; } MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); Modified: trunk/scst/src/dev_handlers/scst_modisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_modisk.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/dev_handlers/scst_modisk.c 2007-08-14 16:54:54 UTC (rev 159) @@ -364,13 +364,14 @@ TRACE_ENTRY(); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; + cmd->status = 0; + cmd->msg_status = 0; + cmd->host_status = DID_OK; + cmd->driver_status = 0; + switch (opcode) { case WRITE_6: case WRITE_10: @@ -380,24 +381,16 @@ case READ_10: case READ_12: case READ_16: - goto out_compl; + cmd->completed = 1; + break; } -out: - TRACE_EXIT_RES(res); - return res; - -out_compl: - cmd->completed = 1; - cmd->status = 0; - cmd->msg_status = 0; - cmd->host_status = DID_OK; - cmd->driver_status = 0; - -out_uncompl: +out_done: res = SCST_EXEC_COMPLETED; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - goto out; + + TRACE_EXIT_RES(res); + return res; } MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); Modified: trunk/scst/src/dev_handlers/scst_tape.c =================================================================== --- trunk/scst/src/dev_handlers/scst_tape.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/dev_handlers/scst_tape.c 2007-08-14 16:54:54 UTC (rev 159) @@ -395,34 +395,27 @@ TRACE_ENTRY(); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; - switch (opcode) { - case WRITE_6: - case READ_6: - goto out_compl; - } - -out: - TRACE_EXIT_RES(res); - return res; - -out_compl: - cmd->completed = 1; cmd->status = 0; cmd->msg_status = 0; cmd->host_status = DID_OK; cmd->driver_status = 0; -out_uncompl: + switch (opcode) { + case WRITE_6: + case READ_6: + cmd->completed = 1; + break; + } + +out_done: res = SCST_EXEC_COMPLETED; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); - goto out; + + TRACE_EXIT_RES(res); + return res; } MODULE_AUTHOR("Vladislav Bolkhovitin & Leonid Stoljar"); Modified: trunk/scst/src/dev_handlers/scst_user.c =================================================================== --- trunk/scst/src/dev_handlers/scst_user.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/dev_handlers/scst_user.c 2007-08-14 16:54:54 UTC (rev 159) @@ -124,6 +124,7 @@ unsigned int buf_dirty:1; unsigned int background_exec:1; unsigned int internal_reset_tm:1; + unsigned int aborted:1; struct dev_user_cmd *buf_ucmd; @@ -842,6 +843,7 @@ ucmd->user_cmd.on_free_cmd.pbuf = ucmd->ubuff; ucmd->user_cmd.on_free_cmd.resp_data_len = cmd->resp_data_len; ucmd->user_cmd.on_free_cmd.buffer_cached = ucmd->buff_cached; + ucmd->user_cmd.on_free_cmd.aborted = ucmd->aborted; ucmd->user_cmd.on_free_cmd.status = cmd->status; ucmd->state = UCMD_STATE_ON_FREEING; @@ -1251,6 +1253,7 @@ out_compl: cmd->completed = 1; cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); + /* !! At this point cmd can be already freed !! */ out: TRACE_EXIT_RES(res); @@ -1445,9 +1448,10 @@ struct dev_user_cmd *__dev_user_get_next_cmd(struct list_head *cmd_list) { - struct dev_user_cmd *u = NULL; + struct dev_user_cmd *u; again: + u = NULL; if (!list_empty(cmd_list)) { u = list_entry(cmd_list->next, typeof(*u), ready_cmd_list_entry); TRACE_DBG("Found ready ucmd %p", u); @@ -1457,12 +1461,17 @@ if (u->state == UCMD_STATE_EXECING) { int rc = scst_check_local_events(u->cmd); if (unlikely(rc != 0)) { - if (rc > 0) { - u->cmd->completed = 1; - u->cmd->scst_cmd_done( - u->cmd, SCST_CMD_STATE_DEFAULT); - } else - dev_user_unjam_cmd(u, 0, NULL); + struct scst_user_dev *dev = u->dev; + spin_unlock_irq( + &dev->cmd_lists.cmd_list_lock); + u->cmd->scst_cmd_done(u->cmd, + SCST_CMD_STATE_DEFAULT); + /* + * !! At this point cmd & u can be !! + * !! already freed !! + */ + spin_lock_irq( + &dev->cmd_lists.cmd_list_lock); goto again; } } else if (unlikely(test_bit(SCST_CMD_ABORTED, @@ -1470,10 +1479,11 @@ switch(u->state) { case UCMD_STATE_PARSING: case UCMD_STATE_BUF_ALLOCING: - case UCMD_STATE_EXECING: TRACE_MGMT_DBG("Aborting ucmd %p", u); dev_user_unjam_cmd(u, 0, NULL); goto again; + case UCMD_STATE_EXECING: + EXTRACHECKS_BUG_ON(1); } } } @@ -1819,11 +1829,15 @@ switch(state) { case UCMD_STATE_PARSING: case UCMD_STATE_BUF_ALLOCING: - if (busy) - scst_set_busy(ucmd->cmd); - else - scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + if (test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags)) + ucmd->aborted = 1; + else { + if (busy) + scst_set_busy(ucmd->cmd); + else + scst_set_cmd_error(ucmd->cmd, + SCST_LOAD_SENSE(scst_sense_hardw_error)); + } TRACE_MGMT_DBG("Adding ucmd %p to active list", ucmd); list_add(&ucmd->cmd->cmd_list_entry, &ucmd->cmd->cmd_lists->active_cmd_list); @@ -1835,15 +1849,23 @@ spin_unlock_irqrestore(&dev->cmd_lists.cmd_list_lock, *flags); else spin_unlock_irq(&dev->cmd_lists.cmd_list_lock); - if (busy) - scst_set_busy(ucmd->cmd); - else - scst_set_cmd_error(ucmd->cmd, - SCST_LOAD_SENSE(scst_sense_hardw_error)); + TRACE_MGMT_DBG("EXEC: unjamming ucmd %p", ucmd); - if (!test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags)) + + if (test_bit(SCST_CMD_ABORTED, &ucmd->cmd->cmd_flags)) + ucmd->aborted = 1; + else { ucmd->cmd->completed = 1; + if (busy) + scst_set_busy(ucmd->cmd); + else + scst_set_cmd_error(ucmd->cmd, + SCST_LOAD_SENSE(scst_sense_hardw_error)); + } + ucmd->cmd->scst_cmd_done(ucmd->cmd, SCST_CMD_STATE_DEFAULT); + /* !! At this point cmd ans ucmd can be already freed !! */ + if (flags != NULL) spin_lock_irqsave(&dev->cmd_lists.cmd_list_lock, *flags); else Modified: trunk/scst/src/dev_handlers/scst_vdisk.c =================================================================== --- trunk/scst/src/dev_handlers/scst_vdisk.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/dev_handlers/scst_vdisk.c 2007-08-14 16:54:54 UTC (rev 159) @@ -652,12 +652,8 @@ TRACE_ENTRY(); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto done; - else - goto done_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; cmd->status = 0; cmd->msg_status = 0; @@ -669,7 +665,7 @@ thr = vdisk_init_thr_data(cmd->tgt_dev); if (thr == NULL) { scst_set_busy(cmd); - goto done; + goto out_compl; } scst_thr_data_get(&thr->hdr); } else @@ -734,7 +730,7 @@ (uint64_t)virt_dev->file_size, (uint64_t)data_len); scst_set_cmd_error(cmd, SCST_LOAD_SENSE( scst_sense_block_out_range_error)); - goto done; + goto out_compl; } switch (opcode) { @@ -780,7 +776,7 @@ (uint64_t)data_len); do_fsync = 1; if (vdisk_fsync(thr, 0, 0, cmd) != 0) - goto done; + goto out_compl; } if (virt_dev->blockio) { blockio_exec_rw(cmd, thr, lba_start, 1); @@ -815,7 +811,7 @@ (uint64_t)data_len); do_fsync = 1; if (vdisk_fsync(thr, 0, 0, cmd) != 0) - goto done; + goto out_compl; } /* ToDo: BLOCKIO VERIFY */ vdisk_exec_write(cmd, thr, loff); @@ -903,10 +899,10 @@ SCST_LOAD_SENSE(scst_sense_invalid_opcode)); } -done: +out_compl: cmd->completed = 1; -done_uncompl: +out_done: cmd->scst_cmd_done(cmd, SCST_CMD_STATE_DEFAULT); out: Modified: trunk/scst/src/scst.c =================================================================== --- trunk/scst/src/scst.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/scst.c 2007-08-14 16:54:54 UTC (rev 159) @@ -52,7 +52,14 @@ not be supported. #endif -/* All targets, devices and dev_types management is done under this mutex */ +/* + * All targets, devices and dev_types management is done under this mutex. + * + * It must NOT be used in any works (schedule_work(), etc.), because + * otherwise a deadlock (double lock, actually) is possible, e.g., with + * scst_user detach_tgt(), which is called under scst_mutex and calls + * flush_scheduled_work(). + */ DEFINE_MUTEX(scst_mutex); LIST_HEAD(scst_template_list); @@ -109,7 +116,8 @@ DECLARE_WAIT_QUEUE_HEAD(scst_mgmt_waitQ); spinlock_t scst_mgmt_lock = SPIN_LOCK_UNLOCKED; -LIST_HEAD(scst_sess_mgmt_list); +LIST_HEAD(scst_sess_init_list); +LIST_HEAD(scst_sess_shut_list); DECLARE_WAIT_QUEUE_HEAD(scst_dev_cmd_waitQ); @@ -369,7 +377,7 @@ mutex_lock(&scst_mutex); list_for_each_entry(sess, &tgt->sess_list, sess_list_entry) { - sBUG_ON(!sess->shutting_down); + sBUG_ON(sess->shut_phase == SCST_SESS_SPH_READY); } mutex_unlock(&scst_mutex); Modified: trunk/scst/src/scst_lib.c =================================================================== --- trunk/scst/src/scst_lib.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/scst_lib.c 2007-08-14 16:54:54 UTC (rev 159) @@ -1048,6 +1048,7 @@ #endif sess->init_phase = SCST_SESS_IPH_INITING; + sess->shut_phase = SCST_SESS_SPH_READY; atomic_set(&sess->refcnt, 0); for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { struct list_head *sess_tgt_dev_list_head = @@ -1137,8 +1138,8 @@ TRACE_ENTRY(); spin_lock_irqsave(&scst_mgmt_lock, flags); - TRACE_DBG("Adding sess %p to scst_sess_mgmt_list", sess); - list_add_tail(&sess->sess_mgmt_list_entry, &scst_sess_mgmt_list); + TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess); + list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list); spin_unlock_irqrestore(&scst_mgmt_lock, flags); wake_up(&scst_mgmt_waitQ); Modified: trunk/scst/src/scst_priv.h =================================================================== --- trunk/scst/src/scst_priv.h 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/scst_priv.h 2007-08-14 16:54:54 UTC (rev 159) @@ -198,7 +198,8 @@ extern wait_queue_head_t scst_mgmt_waitQ; extern spinlock_t scst_mgmt_lock; -extern struct list_head scst_sess_mgmt_list; +extern struct list_head scst_sess_init_list; +extern struct list_head scst_sess_shut_list; struct scst_cmd_thread_t { struct task_struct *cmd_thread; Modified: trunk/scst/src/scst_targ.c =================================================================== --- trunk/scst/src/scst_targ.c 2007-08-10 08:40:54 UTC (rev 158) +++ trunk/scst/src/scst_targ.c 2007-08-14 16:54:54 UTC (rev 159) @@ -61,7 +61,7 @@ TRACE_ENTRY(); #ifdef EXTRACHECKS - if (unlikely(sess->shutting_down)) { + if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) { PRINT_ERROR_PR("%s", "New cmd while shutting down the session"); sBUG(); } @@ -145,7 +145,7 @@ cmd->state = SCST_CMD_STATE_XMIT_RESP; /* Keep initiator away from too many BUSY commands */ if (!in_interrupt() && !in_atomic()) - ssleep(2); + msleep(50); else WARN_ON_ONCE(1); } else { @@ -1287,12 +1287,8 @@ TRACE_ENTRY(); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_done; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; cmd->status = 0; cmd->msg_status = 0; @@ -1366,10 +1362,10 @@ if (dev_cnt < cmd->resp_data_len) scst_set_resp_data_len(cmd, dev_cnt); -out_done: +out_compl: cmd->completed = 1; -out_uncompl: +out_done: /* Report the result */ scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); @@ -1382,12 +1378,12 @@ out_err: scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_invalid_field_in_cdb)); - goto out_done; + goto out_compl; out_put_hw_err: scst_put_buf(cmd, buffer); scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); - goto out_done; + goto out_compl; } static int scst_pre_select(struct scst_cmd *cmd) @@ -1451,12 +1447,8 @@ scst_block_dev_cmd(cmd, 1); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; spin_lock_bh(&dev->dev_lock); @@ -1483,10 +1475,7 @@ TRACE_EXIT_RES(res); return res; -out_compl: - cmd->completed = 1; - -out_uncompl: +out_done: res = SCST_EXEC_COMPLETED; /* Report the result */ scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); @@ -1511,12 +1500,8 @@ scst_block_dev_cmd(cmd, 1); rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_uncompl; - } + if (unlikely(rc != 0)) + goto out_done; spin_lock_bh(&dev->dev_lock); @@ -1544,16 +1529,13 @@ spin_unlock_bh(&dev->dev_lock); if (res == SCST_EXEC_COMPLETED) - goto out_compl; + goto out_done; out: TRACE_EXIT_RES(res); return res; -out_compl: - cmd->completed = 1; - -out_uncompl: +out_done: res = SCST_EXEC_COMPLETED; /* Report the result */ scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); @@ -1629,6 +1611,7 @@ out_complete: res = 1; + cmd->completed = 1; goto out; out_uncomplete: @@ -1786,12 +1769,8 @@ } rc = scst_check_local_events(cmd); - if (unlikely(rc != 0)) { - if (rc > 0) - goto out_compl; - else - goto out_aborted; - } + if (unlikely(rc != 0)) + goto out_done; #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) if (unlikely(scst_alloc_request(cmd) != 0)) { @@ -1845,20 +1824,14 @@ out_error: scst_set_cmd_error(cmd, SCST_LOAD_SENSE(scst_sense_hardw_error)); -out_compl: - cmd->completed = 1; - rc = SCST_EXEC_COMPLETED; - scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); - goto out; - #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18) out_busy: scst_set_busy(cmd); - goto out_compl; - goto out; + cmd->completed = 1; + /* go through */ #endif -out_aborted: +out_done: rc = SCST_EXEC_COMPLETED; /* Report the result. The cmd is not completed */ scst_cmd_done_local(cmd, SCST_CMD_STATE_DEFAULT); @@ -4052,7 +4025,7 @@ atomic_inc(&sess->sess_cmd_count); #ifdef EXTRACHECKS - if (unlikely(sess->shutting_down)) { + if (unlikely(sess->shut_phase != SCST_SESS_SPH_READY)) { PRINT_ERROR_PR("%s", "New mgmt cmd while shutting down the session"); sBUG(); @@ -4346,9 +4319,9 @@ sess->reg_sess_data = data; sess->init_result_fn = result_fn; spin_lock_irqsave(&scst_mgmt_lock, flags); - TRACE_DBG("Adding sess %p to scst_sess_mgmt_list", sess); - list_add_tail(&sess->sess_mgmt_list_entry, - &scst_sess_mgmt_list); + TRACE_DBG("Adding sess %p to scst_sess_init_list", sess); + list_add_tail(&sess->sess_init_list_entry, + &scst_sess_init_list); spin_unlock_irqrestore(&scst_mgmt_lock, flags); wake_up(&scst_mgmt_waitQ); } else { @@ -4367,47 +4340,6 @@ goto out; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -static void scst_unreg_work_fn(void *p) -#else -static void scst_unreg_work_fn(struct work_struct *work) -#endif -{ - int i; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - struct scst_session *sess = (struct scst_session*)p; -#else - struct scst_session *sess = container_of(work, struct scst_session, - unreg_work); -#endif - struct scst_tgt_dev *tgt_dev; - - TRACE_ENTRY(); - - mutex_lock(&scst_mutex); - for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { - struct list_head *sess_tgt_dev_list_head = - &sess->sess_tgt_dev_list_hash[i]; - list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, - sess_tgt_dev_list_entry) { - struct scst_dev_type *handler = tgt_dev->dev->handler; - if (handler && handler->pre_unreg_sess) { - TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", - tgt_dev); - handler->pre_unreg_sess(tgt_dev); - TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " - "returned"); - } - } - } - mutex_unlock(&scst_mutex); - - scst_sess_put(sess); - - TRACE_EXIT(); - return; -} - /* * Must not been called in parallel with scst_rx_cmd() or * scst_rx_mgmt_fn_*() for the same sess @@ -4429,9 +4361,10 @@ pc = &c; #endif + sess->shut_phase = SCST_SESS_SPH_PRE_UNREG; + spin_lock_irqsave(&scst_mgmt_lock, flags); - sess->shutting_down = 1; sess->unreg_done_fn = unreg_done_fn; if (wait) { sess->shutdown_compl = pc; @@ -4446,14 +4379,8 @@ tm_dbg_task_mgmt("UNREGISTER SESSION", 1); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) - INIT_WORK(&sess->unreg_work, scst_unreg_work_fn, sess); -#else - INIT_WORK(&sess->unreg_work, scst_unreg_work_fn); -#endif + scst_sess_put(sess); - schedule_work(&sess->unreg_work); - if (wait) { TRACE_DBG("Waiting for session %p to complete", sess); wait_for_completion(pc); @@ -4467,9 +4394,47 @@ return; } +static void scst_pre_unreg_sess(struct scst_session *sess) +{ + int i; + struct scst_tgt_dev *tgt_dev; + unsigned long flags; + + TRACE_ENTRY(); + + mutex_lock(&scst_mutex); + for(i = 0; i < TGT_DEV_HASH_SIZE; i++) { + struct list_head *sess_tgt_dev_list_head = + &sess->sess_tgt_dev_list_hash[i]; + list_for_each_entry(tgt_dev, sess_tgt_dev_list_head, + sess_tgt_dev_list_entry) { + struct scst_dev_type *handler = tgt_dev->dev->handler; + if (handler && handler->pre_unreg_sess) { + TRACE_DBG("Calling dev handler's pre_unreg_sess(%p)", + tgt_dev); + handler->pre_unreg_sess(tgt_dev); + TRACE_DBG("%s", "Dev handler's pre_unreg_sess() " + "returned"); + } + } + } + mutex_unlock(&scst_mutex); + + sess->shut_phase = SCST_SESS_SPH_SHUTDOWN; + + spin_lock_irqsave(&scst_mgmt_lock, flags); + TRACE_DBG("Adding sess %p to scst_sess_shut_list", sess); + list_add_tail(&sess->sess_shut_list_entry, &scst_sess_shut_list); + spin_unlock_irqrestore(&scst_mgmt_lock, flags); + + TRACE_EXIT(); + return; +} + static inline int test_mgmt_list(void) { - int res = !list_empty(&scst_sess_mgmt_list) || + int res = !list_empty(&scst_sess_init_list) || + !list_empty(&scst_sess_shut_list) || unlikely(kthread_should_stop()); return res; } @@ -4500,36 +4465,64 @@ set_current_state(TASK_RUNNING); remove_wait_queue(&scst_mgmt_waitQ, &wait); } -restart: - list_for_each_entry(sess, &scst_sess_mgmt_list, - sess_mgmt_list_entry) - { - TRACE_DBG("Removing sess %p from scst_sess_mgmt_list", + + while (!list_empty(&scst_sess_init_list)) { + sess = list_entry(scst_sess_init_list.next, + typeof(*sess), sess_init_list_entry); + TRACE_DBG("Removing sess %p from scst_sess_init_list", sess); - list_del(&sess->sess_mgmt_list_entry); + list_del(&sess->sess_init_list_entry); spin_unlock_irq(&scst_mgmt_lock); - if (sess->init_phase == SCST_SESS_IPH_INITING) { + + if (sess->init_phase == SCST_SESS_IPH_INITING) scst_init_session(sess); - } else if (sess->shutting_down) { + else { + PRINT_ERROR_PR("session %p is in " + "scst_sess_init_list, but in unknown " + "init phase %x", sess, + sess->init_phase); + sBUG(); + } + + spin_lock_irq(&scst_mgmt_lock); + } + + while (!list_empty(&scst_sess_shut_list)) { + sess = list_entry(scst_sess_shut_list.next, + typeof(*sess), sess_shut_list_entry); + TRACE_DBG("Removing sess %p from scst_sess_shut_list", + sess); + list_del(&sess->sess_shut_list_entry); + spin_unlock_irq(&scst_mgmt_lock); + + switch(sess->shut_phase) { + case SCST_SESS_SPH_PRE_UNREG: + scst_pre_unreg_sess(sess); + break; + case SCST_SESS_SPH_SHUTDOWN: sBUG_ON(atomic_read(&sess->refcnt) != 0); scst_free_session_callback(sess); - } else { + break; + default: PRINT_ERROR_PR("session %p is in " - "scst_sess_mgmt_list, but in unknown " - "phase %x", sess, sess->init_phase); + "scst_sess_shut_list, but in unknown " + "shut phase %lx", sess, + sess->shut_phase); sBUG(); + break; } + spin_lock_irq(&scst_mgmt_lock); - goto restart; } } spin_unlock_irq(&scst_mgmt_lock); /* * If kthread_should_stop() is true, we are guaranteed to be - * on the module unload, so scst_sess_mgmt_list must be empty. + * on the module unload, so both lists must be empty. */ - sBUG_ON(!list_empty(&scst_sess_mgmt_list)); + sBUG_ON(!list_empty(&scst_sess_init_list)); + sBUG_ON(!list_empty(&scst_sess_shut_list)); TRACE_EXIT(); return 0; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |