📄 zfcp_erp.c
字号:
} } else { debug_text_event(adapter->erp_dbf, 3, "a_ca_gonereq"); /* * even if this fsf_req has gone, forget about * association between erp_action and fsf_req */ erp_action->fsf_req = NULL; } spin_unlock(&adapter->fsf_req_list_lock); } else debug_text_event(adapter->erp_dbf, 3, "a_ca_noreq"); return retval;}/* * purpose: generic handler for asynchronous events related to erp_action events * (normal completion, time-out, dismissing, retry after * low memory condition) * * note: deletion of timer is not required (e.g. in case of a time-out), * but a second try does no harm, * we leave it in here to allow for greater simplification * * returns: 0 - there was an action to handle * !0 - otherwise */static intzfcp_erp_async_handler_nolock(struct zfcp_erp_action *erp_action, unsigned long set_mask){ int retval; struct zfcp_adapter *adapter = erp_action->adapter; if (zfcp_erp_action_exists(erp_action) == ZFCP_ERP_ACTION_RUNNING) { debug_text_event(adapter->erp_dbf, 2, "a_asyh_ex"); debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); if (!(set_mask & ZFCP_STATUS_ERP_TIMEDOUT)) del_timer(&erp_action->timer); erp_action->status |= set_mask; zfcp_erp_action_ready(erp_action); retval = 0; } else { /* action is ready or gone - nothing to do */ debug_text_event(adapter->erp_dbf, 3, "a_asyh_gone"); debug_event(adapter->erp_dbf, 3, &erp_action->action, sizeof (int)); retval = 1; } return retval;}/* * purpose: generic handler for asynchronous events related to erp_action * events (normal completion, time-out, dismissing, retry after * low memory condition) * * note: deletion of timer is not required (e.g. in case of a time-out), * but a second try does no harm, * we leave it in here to allow for greater simplification * * returns: 0 - there was an action to handle * !0 - otherwise */intzfcp_erp_async_handler(struct zfcp_erp_action *erp_action, unsigned long set_mask){ struct zfcp_adapter *adapter = erp_action->adapter; unsigned long flags; int retval; write_lock_irqsave(&adapter->erp_lock, flags); retval = zfcp_erp_async_handler_nolock(erp_action, set_mask); write_unlock_irqrestore(&adapter->erp_lock, flags); return retval;}/* * purpose: is called for erp_action which was slept waiting for * memory becoming avaliable, * will trigger that this action will be continued */static voidzfcp_erp_memwait_handler(unsigned long data){ struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; debug_text_event(adapter->erp_dbf, 2, "a_mwh"); debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); zfcp_erp_async_handler(erp_action, 0);}/* * purpose: is called if an asynchronous erp step timed out, * action gets an appropriate flag and will be processed * accordingly */static voidzfcp_erp_timeout_handler(unsigned long data){ struct zfcp_erp_action *erp_action = (struct zfcp_erp_action *) data; struct zfcp_adapter *adapter = erp_action->adapter; debug_text_event(adapter->erp_dbf, 2, "a_th"); debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); zfcp_erp_async_handler(erp_action, ZFCP_STATUS_ERP_TIMEDOUT);}/* * purpose: is called for an erp_action which needs to be ended * though not being done, * this is usually required if an higher is generated, * action gets an appropriate flag and will be processed * accordingly * * locks: erp_lock held (thus we need to call another handler variant) */static intzfcp_erp_action_dismiss(struct zfcp_erp_action *erp_action){ struct zfcp_adapter *adapter = erp_action->adapter; debug_text_event(adapter->erp_dbf, 2, "a_adis"); debug_event(adapter->erp_dbf, 2, &erp_action->action, sizeof (int)); zfcp_erp_async_handler_nolock(erp_action, ZFCP_STATUS_ERP_DISMISSED); return 0;}intzfcp_erp_thread_setup(struct zfcp_adapter *adapter){ int retval = 0; atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); retval = kernel_thread(zfcp_erp_thread, adapter, SIGCHLD); if (retval < 0) { ZFCP_LOG_NORMAL("error: creation of erp thread failed for " "adapter %s\n", zfcp_get_busid_by_adapter(adapter)); debug_text_event(adapter->erp_dbf, 5, "a_thset_fail"); } else { wait_event(adapter->erp_thread_wqh, atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status)); debug_text_event(adapter->erp_dbf, 5, "a_thset_ok"); } return (retval < 0);}/* * function: * * purpose: * * returns: * * context: process (i.e. proc-fs or rmmod/insmod) * * note: The caller of this routine ensures that the specified * adapter has been shut down and that this operation * has been completed. Thus, there are no pending erp_actions * which would need to be handled here. */intzfcp_erp_thread_kill(struct zfcp_adapter *adapter){ int retval = 0; atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); up(&adapter->erp_ready_sem); wait_event(adapter->erp_thread_wqh, !atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status)); atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status); debug_text_event(adapter->erp_dbf, 5, "a_thki_ok"); return retval;}/* * purpose: is run as a kernel thread, * goes through list of error recovery actions of associated adapter * and delegates single action to execution * * returns: 0 */static intzfcp_erp_thread(void *data){ struct zfcp_adapter *adapter = (struct zfcp_adapter *) data; struct list_head *next; struct zfcp_erp_action *erp_action; unsigned long flags; daemonize("zfcperp%s", zfcp_get_busid_by_adapter(adapter)); /* Block all signals */ siginitsetinv(¤t->blocked, 0); atomic_set_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); debug_text_event(adapter->erp_dbf, 5, "a_th_run"); wake_up(&adapter->erp_thread_wqh); while (!atomic_test_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_KILL, &adapter->status)) { write_lock_irqsave(&adapter->erp_lock, flags); next = adapter->erp_ready_head.prev; write_unlock_irqrestore(&adapter->erp_lock, flags); if (next != &adapter->erp_ready_head) { erp_action = list_entry(next, struct zfcp_erp_action, list); /* * process action (incl. [re]moving it * from 'ready' queue) */ zfcp_erp_strategy(erp_action); } /* * sleep as long as there is nothing to do, i.e. * no action in 'ready' queue to be processed and * thread is not to be killed */ down_interruptible(&adapter->erp_ready_sem); debug_text_event(adapter->erp_dbf, 5, "a_th_woken"); } atomic_clear_mask(ZFCP_STATUS_ADAPTER_ERP_THREAD_UP, &adapter->status); debug_text_event(adapter->erp_dbf, 5, "a_th_stop"); wake_up(&adapter->erp_thread_wqh); return 0;}/* * function: * * purpose: drives single error recovery action and schedules higher and * subordinate actions, if necessary * * returns: ZFCP_ERP_CONTINUES - action continues (asynchronously) * ZFCP_ERP_SUCCEEDED - action finished successfully (deqd) * ZFCP_ERP_FAILED - action finished unsuccessfully (deqd) * ZFCP_ERP_EXIT - action finished (dequeued), offline * ZFCP_ERP_DISMISSED - action canceled (dequeued) */static intzfcp_erp_strategy(struct zfcp_erp_action *erp_action){ int retval = 0; struct zfcp_adapter *adapter = erp_action->adapter; struct zfcp_port *port = erp_action->port; struct zfcp_unit *unit = erp_action->unit; int action = erp_action->action; u32 status = erp_action->status; unsigned long flags; /* serialise dismissing, timing out, moving, enqueueing */ read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); /* dequeue dismissed action and leave, if required */ retval = zfcp_erp_strategy_check_action(erp_action, retval); if (retval == ZFCP_ERP_DISMISSED) { debug_text_event(adapter->erp_dbf, 4, "a_st_dis1"); goto unlock; } /* * move action to 'running' queue before processing it * (to avoid a race condition regarding moving the * action to the 'running' queue and back) */ zfcp_erp_action_to_running(erp_action); /* * try to process action as far as possible, * no lock to allow for blocking operations (kmalloc, qdio, ...), * afterwards the lock is required again for the following reasons: * - dequeueing of finished action and enqueueing of * follow-up actions must be atomic so that any other * reopen-routine does not believe there is nothing to do * and that it is safe to enqueue something else, * - we want to force any control thread which is dismissing * actions to finish this before we decide about * necessary steps to be taken here further */ write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); retval = zfcp_erp_strategy_do_action(erp_action); read_lock_irqsave(&zfcp_data.config_lock, flags); write_lock(&adapter->erp_lock); /* * check for dismissed status again to avoid follow-up actions, * failing of targets and so on for dismissed actions */ retval = zfcp_erp_strategy_check_action(erp_action, retval); switch (retval) { case ZFCP_ERP_DISMISSED: /* leave since this action has ridden to its ancestors */ debug_text_event(adapter->erp_dbf, 6, "a_st_dis2"); goto unlock; case ZFCP_ERP_NOMEM: /* no memory to continue immediately, let it sleep */ if (!(erp_action->status & ZFCP_STATUS_ERP_LOWMEM)) { ++adapter->erp_low_mem_count; erp_action->status |= ZFCP_STATUS_ERP_LOWMEM; } /* This condition is true if there is no memory available for any erp_action on this adapter. This implies that there are no elements in the memory pool(s) left for erp_actions. This might happen if an erp_action that used a memory pool element was timed out. */ if (adapter->erp_total_count == adapter->erp_low_mem_count) { debug_text_event(adapter->erp_dbf, 3, "a_st_lowmem"); ZFCP_LOG_NORMAL("error: no mempool elements available, " "restarting I/O on adapter %s " "to free mempool\n", zfcp_get_busid_by_adapter(adapter)); zfcp_erp_adapter_reopen_internal(adapter, 0); } else { debug_text_event(adapter->erp_dbf, 2, "a_st_memw"); retval = zfcp_erp_strategy_memwait(erp_action); } goto unlock; case ZFCP_ERP_CONTINUES: /* leave since this action runs asynchronously */ debug_text_event(adapter->erp_dbf, 6, "a_st_cont"); if (erp_action->status & ZFCP_STATUS_ERP_LOWMEM) { --adapter->erp_low_mem_count; erp_action->status &= ~ZFCP_STATUS_ERP_LOWMEM; } goto unlock; } /* ok, finished action (whatever its result is) */ /* check for unrecoverable targets */ retval = zfcp_erp_strategy_check_target(erp_action, retval); /* action must be dequeued (here to allow for further ones) */ zfcp_erp_action_dequeue(erp_action); /* * put this target through the erp mill again if someone has * requested to change the status of a target being online * to offline or the other way around * (old retval is preserved if nothing has to be done here) */ retval = zfcp_erp_strategy_statechange(action, status, adapter, port, unit, retval); /* * leave if target is in permanent error state or if * action is repeated in order to process state change */ if (retval == ZFCP_ERP_EXIT) { debug_text_event(adapter->erp_dbf, 2, "a_st_exit"); goto unlock; } /* trigger follow up actions */ zfcp_erp_strategy_followup_actions(action, adapter, port, unit, retval); unlock: write_unlock(&adapter->erp_lock); read_unlock_irqrestore(&zfcp_data.config_lock, flags); if (retval != ZFCP_ERP_CONTINUES) zfcp_erp_action_cleanup(action, adapter, port, unit, retval); /* * a few tasks remain when the erp queues are empty * (don't do that if the last action evaluated was dismissed * since this clearly indicates that there is more to come) : * - close the name server port if it is open yet * (enqueues another [probably] final action) * - otherwise, wake up whoever wants to be woken when we are * done with erp */ if (retval != ZFCP_ERP_DISMISSED) zfcp_erp_strategy_check_queues(adapter); debug_text_event(adapter->erp_dbf, 6, "a_st_done"); return retval;}/* * function: * * purpose: * * returns: ZFCP_ERP_DISMISSED - if action has been dismissed * retval - otherwise */static intzfcp_erp_strategy_check_action(struct zfcp_erp_action *erp_action, int retval){ struct zfcp_adapter *adapter = erp_action->adapter; zfcp_erp_strategy_check_fsfreq(erp_action); debug_event(adapter->erp_dbf, 5, &erp_action->action, sizeof (int)); if (erp_action->status & ZFCP_STATUS_ERP_DISMISSED) { debug_text_event(adapter->erp_dbf, 3, "a_stcd_dis"); zfcp_erp_action_dequeue(erp_action); retval = ZFCP_ERP_DISMISSED; } else debug_text_event(adapter->erp_dbf, 5, "a_stcd_nodis"); return retval;}/* * function: * * purpose: * * returns: */static intzfcp_erp_strategy_do_action(struct zfcp_erp_action *erp_action){ int retval = ZFCP_ERP_FAILED; struct zfcp_adapter *adapter = erp_action->adapter; /* * try to execute/continue action as far as possible, * note: no lock in subsequent strategy routines * (this allows these routine to call schedule, e.g. * kmalloc with such flags or qdio_initialize & friends) * Note: in case of timeout, the seperate strategies will fail * anyhow. No need for a special action. Even worse, a nameserver * failure would not wake up waiting ports without the call. */ switch (erp_action->action) { case ZFCP_ERP_ACTION_REOPEN_ADAPTER: retval = zfcp_erp_adapter_strategy(erp_action); break; case ZFCP_ERP_ACTION_REOPEN_PORT_FORCED: retval = zfcp_erp_port_forced_strategy(erp_action); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -