/*********************************************************************** F* Function: int wd_reset_mon_chain(int chainid) P*A*Z* * P* Parameters: int chainid P* - The id of the chain to reset P* P* Returnvalue: int P* - 0 The chain was reset suiccessfully P* <0 Errorcondition, which can be P* -EINVAL The supplied id is unknown. * Z* Intention: This function resets a chain to its initial state. Z* The function is called through the ioctl() mechanism Z* to reset or trigger a chain or directly from other Z* kernel proper, as it is exported. * D* Design: [email protected] C* Coding: [email protected] V* Verification: [email protected] ***********************************************************************/ int wd_reset_mon_chain(int chainid) { monitored_chain_t *entry; int result = 0; debugk("%s: WD monitor reset for id %d\n", __FUNCTION__, chainid); spin_lock(&mon_lock); if ((entry = find_mon_chain_by_chainid(chainid)) == NULL) { result = -EINVAL; goto out; } entry->escalation = 0; entry->expires = jiffies + HZ * entry->timer_count[0]; list_del(&entry->list); insert_mon_chain(entry); out: spin_unlock(&mon_lock); return result; }
/*********************************************************************** F* Function: static int register_mon_chain(wdt_mpc8xx_param_t *param, F* int userproc) P*A*Z* * P* Parameters: wdt_mpc8xx_param_t *param P* - The parameters for the chain to be registered. P* Unused stages should be cleared with 0's. P* int userproc P* - Flag whether we are called from user or kernel space P* P* Returnvalue: int P* - 0 success P* -EINVAL invalid parameters P* -ENOMEM out of memory * Z* Intention: This is the main interface to register a watchdog chain Z* either from userspace throught ioctl() or from kernel Z* space through the wrapper function Z* wdt_mpc8x_register_mon_chain(). Z* Re-registering an existing chain is explicitely ok, as Z* a restarted process has to go through this. This Z* effectively resets the corresponding chain. Z* For a detailed description of the parameters, see the Z* wdt_mpc8xx(4) manpage. * D* Design: [email protected] C* Coding: [email protected] V* Verification: [email protected] ***********************************************************************/ static int register_mon_chain(wdt_mpc8xx_param_t *param, int userproc) { monitored_chain_t *entry; int result=0, i; /* Before kmallocing storage we first check the parameters */ for (i=0; (i<3)&&(param->timer_count[i]); i++) if ((param->action[i]<WDT_MPC8XX_ACTION_SIGNAL)|| (param->action[i]>WDT_MPC8XX_ACTION_RESET)) return(-EINVAL); debugk("%s: registering WDT8xx monitor\n", __FUNCTION__); spin_lock(&mon_lock); if ((entry=find_mon_chain_by_chainid(param->chainid))==NULL) { /* New chain-id so allocate list entry */ entry=(monitored_chain_t *)kmalloc(sizeof(monitored_chain_t), GFP_KERNEL); if (entry==NULL) { result=-ENOMEM; goto out; } /* Copy request data to internal format */ if (userproc) entry->pid=current->pid; else entry->pid=0; entry->chainid=param->chainid; entry->signal=param->signal; for (i=0; i<2 ; i++) { if (entry->action[i]!=0) { entry->timer_count[i]=param->timer_count[i]; entry->action[i]=param->action[i]; } else { /* Fill with stop entries */ entry->timer_count[i]=2; entry->action[i]=WDT_MPC8XX_ACTION_RESET; } } /* This is a final stop entry */ entry->timer_count[3]=2; entry->action[3]=WDT_MPC8XX_ACTION_RESET; /* Initialize internal data */ entry->escalation=0; entry->expires=jiffies + HZ * entry->timer_count[0]; insert_mon_chain(entry); mon_chains++; } else { /* Re-registering of active monitor */ entry->pid=current->pid; entry->escalation=0; entry->expires=jiffies + HZ * entry->timer_count[0]; entry->escalation=0; list_del(&entry->list); insert_mon_chain(entry); } out: spin_unlock(&mon_lock); return(result); }
/*********************************************************************** F* Function: static int process_mon_chains(void) P*A*Z* * P* Parameters: none P* P* Returnvalue: int P* - 0 if the function returns at all * Z* Intention: This is the core function of the chain functionality. Z* The list with the monitored chain is processed and Z* expired entries handled appropriately by stepping up Z* the escalation ladder. The escalation actions are Z* triggered from here. * D* Design: [email protected] C* Coding: [email protected] V* Verification: [email protected] ***********************************************************************/ static int process_mon_chains(void) { struct list_head *ptr; monitored_chain_t *entry; int sig; spin_lock(&mon_lock); for (ptr=mon_list.next; ptr!=&mon_list; ptr=ptr->next) { entry=list_entry(ptr, monitored_chain_t, list); if (entry->expires<=jiffies) { debugk("%s: WDT8xx monitor expired for id %d\n", __FUNCTION__, entry->chainid); switch (entry->action[entry->escalation]) { case WDT_MPC8XX_ACTION_SIGNAL: debugk("WDT_8xx: sending user signal for key %d...\n", entry->chainid); sig=(entry->signal)?entry->signal:SIGTERM; if (entry->pid) kill_proc(entry->pid, sig, 1); break; case WDT_MPC8XX_ACTION_KILL: debugk("WDT_8xx: sending KILL signal for key %d...\n", entry->chainid); if (entry->pid) kill_proc(entry->pid, SIGKILL, 1); break; case WDT_MPC8XX_ACTION_REBOOT: spin_unlock(&mon_lock); wdt_mpc8xx_unregister_mon_chain(entry->chainid); printk("WDT_8xx: Rebooting system for key %d...\n", entry->chainid); sync(); sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, NULL); break; case WDT_MPC8XX_ACTION_RESET: printk("WDT_8xx: Resetting system for key %d...\n", entry->chainid); #ifdef CONFIG_8xx m8xx_restart (NULL); #else machine_restart (NULL); #endif break; default: debugk("WDT_8xx: undefined action %d\n", entry->action[entry->escalation]); break; } entry->escalation++; entry->expires=jiffies + HZ * entry->timer_count[entry->escalation]; list_del(&entry->list); insert_mon_chain(entry); } else /* The list is sorted, so we can stop here */ break; } spin_unlock(&mon_lock); return(0); }
/*********************************************************************** F* Function: static int process_mon_chains(void) P*A*Z* * P* Parameters: none P* P* Returnvalue: int P* - 0 if the function returns at all * Z* Intention: This is the core function of the chain functionality. Z* The list with the monitored chain is processed and Z* expired entries handled appropriately by stepping up Z* the escalation ladder. The escalation actions are Z* triggered from here. * D* Design: [email protected] C* Coding: [email protected] V* Verification: [email protected] ***********************************************************************/ static int process_mon_chains(void) { struct list_head *ptr; monitored_chain_t *entry; int sig; spin_lock(&mon_lock); for (ptr = mon_list.next; ptr != &mon_list; ptr = ptr->next) { entry = list_entry(ptr, monitored_chain_t, list); if (time_after_eq(jiffies, entry->expires)) { debugk("%s: WD monitor expired for id %d\n", __FUNCTION__, entry->chainid); switch (entry->action[entry->escalation]) { case WD_ACTION_SIGNAL: debugk("WD: sending user signal for key " "%d...\n", entry->chainid); sig = (entry->signal) ? entry->signal : SIGTERM; if (entry->pid) kill_proc_info(sig, SEND_SIG_PRIV, entry->pid); break; case WD_ACTION_KILL: debugk("WD: sending KILL signal for key " "%d...\n", entry->chainid); if (entry->pid) kill_proc_info(SIGKILL, SEND_SIG_PRIV, entry->pid); break; case WD_ACTION_REBOOT: spin_unlock(&mon_lock); wd_unregister_mon_chain(entry->chainid); printk("WD: Rebooting system for key " "%d...\n", entry->chainid); flush_cache_all(); /* * XXX This is not safe to call in interrupt * context. */ sys_reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART, NULL); break; case WD_ACTION_RESET: printk("WD: Resetting system for key " "%d...\n", entry->chainid); BUG_ON(wd_hw_functions.wd_machine_restart == NULL); wd_hw_functions.wd_machine_restart(); break; default: debugk("WD: undefined action %d\n", entry->action[entry->escalation]); break; } entry->escalation++; entry->expires = jiffies + HZ * entry->timer_count[entry->escalation]; list_del(&entry->list); insert_mon_chain(entry); } else /* The list is sorted, so we can stop here */ break; } spin_unlock(&mon_lock); return 0; }