浏览代码

[SCSI] zfcp: fix race conditions when accessing erp_action lists

o always use locking when changing erp_action lists,
o avoid escalation to ERP_ACTION_REOPEN_PORT_FORCED if erp_action is
  still in use for ERP_ACTION_REOPEN_PORT

Signed-off-by: Andreas Herrmann <aherrman@de.ibm.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Andreas Herrmann 19 年之前
父节点
当前提交
3734d24b2e
共有 1 个文件被更改,包括 17 次插入7 次删除
  1. 17 7
      drivers/s390/scsi/zfcp_erp.c

+ 17 - 7
drivers/s390/scsi/zfcp_erp.c

@@ -886,7 +886,7 @@ static int
 zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 {
 {
 	int retval = 0;
 	int retval = 0;
-	struct zfcp_fsf_req *fsf_req;
+	struct zfcp_fsf_req *fsf_req = NULL;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 	struct zfcp_adapter *adapter = erp_action->adapter;
 
 
 	if (erp_action->fsf_req) {
 	if (erp_action->fsf_req) {
@@ -896,7 +896,7 @@ zfcp_erp_strategy_check_fsfreq(struct zfcp_erp_action *erp_action)
 		list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
 		list_for_each_entry(fsf_req, &adapter->fsf_req_list_head, list)
 		    if (fsf_req == erp_action->fsf_req)
 		    if (fsf_req == erp_action->fsf_req)
 			break;
 			break;
-		if (fsf_req == erp_action->fsf_req) {
+		if (fsf_req && (fsf_req->erp_action == erp_action)) {
 			/* fsf_req still exists */
 			/* fsf_req still exists */
 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
 			debug_text_event(adapter->erp_dbf, 3, "a_ca_req");
 			debug_event(adapter->erp_dbf, 3, &fsf_req,
 			debug_event(adapter->erp_dbf, 3, &fsf_req,
@@ -2291,7 +2291,9 @@ zfcp_erp_adapter_strategy_open_fsf_xconfig(struct zfcp_erp_action *erp_action)
 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
 		atomic_clear_mask(ZFCP_STATUS_ADAPTER_HOST_CON_INIT,
 				  &adapter->status);
 				  &adapter->status);
 		ZFCP_LOG_DEBUG("Doing exchange config data\n");
 		ZFCP_LOG_DEBUG("Doing exchange config data\n");
+		write_lock(&adapter->erp_lock);
 		zfcp_erp_action_to_running(erp_action);
 		zfcp_erp_action_to_running(erp_action);
+		write_unlock(&adapter->erp_lock);
 		zfcp_erp_timeout_init(erp_action);
 		zfcp_erp_timeout_init(erp_action);
 		if (zfcp_fsf_exchange_config_data(erp_action)) {
 		if (zfcp_fsf_exchange_config_data(erp_action)) {
 			retval = ZFCP_ERP_FAILED;
 			retval = ZFCP_ERP_FAILED;
@@ -3194,11 +3196,19 @@ zfcp_erp_action_enqueue(int action,
 		/* fall through !!! */
 		/* fall through !!! */
 
 
 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
 	case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED:
-		if (atomic_test_mask
-		    (ZFCP_STATUS_COMMON_ERP_INUSE, &port->status)
-		    && port->erp_action.action ==
-		    ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
-			debug_text_event(adapter->erp_dbf, 4, "pf_actenq_drp");
+		if (atomic_test_mask(ZFCP_STATUS_COMMON_ERP_INUSE,
+				     &port->status)) {
+			if (port->erp_action.action !=
+			    ZFCP_ERP_ACTION_REOPEN_PORT_FORCED) {
+				ZFCP_LOG_INFO("dropped erp action %i (port "
+					      "0x%016Lx, action in use: %i)\n",
+					      action, port->wwpn,
+					      port->erp_action.action);
+				debug_text_event(adapter->erp_dbf, 4,
+						 "pf_actenq_drp");
+			} else 
+				debug_text_event(adapter->erp_dbf, 4,
+						 "pf_actenq_drpcp");
 			debug_event(adapter->erp_dbf, 4, &port->wwpn,
 			debug_event(adapter->erp_dbf, 4, &port->wwpn,
 				    sizeof (wwn_t));
 				    sizeof (wwn_t));
 			goto out;
 			goto out;