欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

ipmi_watchdog.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
		       msg->msg.cmd);	}		ipmi_free_recv_msg(msg);}static void ipmi_wdog_pretimeout_handler(void *handler_data){	if (preaction_val != WDOG_PRETIMEOUT_NONE) {		if (preop_val == WDOG_PREOP_PANIC) {			if (atomic_inc_and_test(&preop_panic_excl))				panic("Watchdog pre-timeout");		} else if (preop_val == WDOG_PREOP_GIVE_DATA) {			spin_lock(&ipmi_read_lock);			data_to_read = 1;			wake_up_interruptible(&read_q);			kill_fasync(&fasync_q, SIGIO, POLL_IN);			spin_unlock(&ipmi_read_lock);		}	}	/* On some machines, the heartbeat will give	   an error and not work unless we re-enable	   the timer.   So do so. */	pretimeout_since_last_heartbeat = 1;}static struct ipmi_user_hndl ipmi_hndlrs ={	.ipmi_recv_hndl           = ipmi_wdog_msg_handler,	.ipmi_watchdog_pretimeout = ipmi_wdog_pretimeout_handler};static void ipmi_register_watchdog(int ipmi_intf){	int rv = -EBUSY;	if (watchdog_user)		goto out;	if ((ifnum_to_use >= 0) && (ifnum_to_use != ipmi_intf))		goto out;	watchdog_ifnum = ipmi_intf;	rv = ipmi_create_user(ipmi_intf, &ipmi_hndlrs, NULL, &watchdog_user);	if (rv < 0) {		printk(KERN_CRIT PFX "Unable to register with ipmi\n");		goto out;	}	ipmi_get_version(watchdog_user,			 &ipmi_version_major,			 &ipmi_version_minor);	rv = misc_register(&ipmi_wdog_miscdev);	if (rv < 0) {		ipmi_destroy_user(watchdog_user);		watchdog_user = NULL;		printk(KERN_CRIT PFX "Unable to register misc device\n");	}#ifdef HAVE_DIE_NMI	if (nmi_handler_registered) {		int old_pretimeout = pretimeout;		int old_timeout = timeout;		int old_preop_val = preop_val;		/* Set the pretimeout to go off in a second and give		   ourselves plenty of time to stop the timer. */		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;		preop_val = WDOG_PREOP_NONE; /* Make sure nothing happens */		pretimeout = 99;		timeout = 100;		testing_nmi = 1;		rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);		if (rv) {			printk(KERN_WARNING PFX "Error starting timer to"			       " test NMI: 0x%x.  The NMI pretimeout will"			       " likely not work\n", rv);			rv = 0;			goto out_restore;		}		msleep(1500);		if (testing_nmi != 2) {			printk(KERN_WARNING PFX "IPMI NMI didn't seem to"			       " occur.  The NMI pretimeout will"			       " likely not work\n");		}	out_restore:		testing_nmi = 0;		preop_val = old_preop_val;		pretimeout = old_pretimeout;		timeout = old_timeout;	}#endif out:	if ((start_now) && (rv == 0)) {		/* Run from startup, so start the timer now. */		start_now = 0; /* Disable this function after first startup. */		ipmi_watchdog_state = action_val;		ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);		printk(KERN_INFO PFX "Starting now!\n");	} else {		/* Stop the timer now. */		ipmi_watchdog_state = WDOG_TIMEOUT_NONE;		ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);	}}static void ipmi_unregister_watchdog(int ipmi_intf){	int rv;	if (!watchdog_user)		goto out;	if (watchdog_ifnum != ipmi_intf)		goto out;	/* Make sure no one can call us any more. */	misc_deregister(&ipmi_wdog_miscdev);	/* Wait to make sure the message makes it out.  The lower layer has	   pointers to our buffers, we want to make sure they are done before	   we release our memory. */	while (atomic_read(&set_timeout_tofree))		schedule_timeout_uninterruptible(1);	/* Disconnect from IPMI. */	rv = ipmi_destroy_user(watchdog_user);	if (rv) {		printk(KERN_WARNING PFX "error unlinking from IPMI: %d\n",		       rv);	}	watchdog_user = NULL; out:	return;}#ifdef HAVE_DIE_NMIstatic intipmi_nmi(struct notifier_block *self, unsigned long val, void *data){	struct die_args *args = data;	if (val != DIE_NMI)		return NOTIFY_OK;	/* Hack, if it's a memory or I/O error, ignore it. */	if (args->err & 0xc0)		return NOTIFY_OK;	/*	 * If we get here, it's an NMI that's not a memory or I/O	 * error.  We can't truly tell if it's from IPMI or not	 * without sending a message, and sending a message is almost	 * impossible because of locking.	 */	if (testing_nmi) {		testing_nmi = 2;		return NOTIFY_STOP;	}        /* If we are not expecting a timeout, ignore it. */	if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)		return NOTIFY_OK;	if (preaction_val != WDOG_PRETIMEOUT_NMI)		return NOTIFY_OK;	/* If no one else handled the NMI, we assume it was the IPMI           watchdog. */	if (preop_val == WDOG_PREOP_PANIC) {		/* On some machines, the heartbeat will give		   an error and not work unless we re-enable		   the timer.   So do so. */		pretimeout_since_last_heartbeat = 1;		if (atomic_inc_and_test(&preop_panic_excl))			panic(PFX "pre-timeout");	}	return NOTIFY_STOP;}static struct notifier_block ipmi_nmi_handler = {	.notifier_call = ipmi_nmi};#endifstatic int wdog_reboot_handler(struct notifier_block *this,			       unsigned long         code,			       void                  *unused){	static int reboot_event_handled = 0;	if ((watchdog_user) && (!reboot_event_handled)) {		/* Make sure we only do this once. */		reboot_event_handled = 1;		if (code == SYS_POWER_OFF || code == SYS_HALT) {			/* Disable the WDT if we are shutting down. */			ipmi_watchdog_state = WDOG_TIMEOUT_NONE;			panic_halt_ipmi_set_timeout();		} else if (ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {			/* Set a long timer to let the reboot happens, but			   reboot if it hangs, but only if the watchdog			   timer was already running. */			timeout = 120;			pretimeout = 0;			ipmi_watchdog_state = WDOG_TIMEOUT_RESET;			panic_halt_ipmi_set_timeout();		}	}	return NOTIFY_OK;}static struct notifier_block wdog_reboot_notifier = {	.notifier_call	= wdog_reboot_handler,	.next		= NULL,	.priority	= 0};static int wdog_panic_handler(struct notifier_block *this,			      unsigned long         event,			      void                  *unused){	static int panic_event_handled = 0;	/* On a panic, if we have a panic timeout, make sure to extend	   the watchdog timer to a reasonable value to complete the	   panic, if the watchdog timer is running.  Plus the	   pretimeout is meaningless at panic time. */	if (watchdog_user && !panic_event_handled &&	    ipmi_watchdog_state != WDOG_TIMEOUT_NONE) {		/* Make sure we do this only once. */		panic_event_handled = 1;	    		timeout = 255;		pretimeout = 0;		panic_halt_ipmi_set_timeout();	}	return NOTIFY_OK;}static struct notifier_block wdog_panic_notifier = {	.notifier_call	= wdog_panic_handler,	.next		= NULL,	.priority	= 150	/* priority: INT_MAX >= x >= 0 */};static void ipmi_new_smi(int if_num, struct device *device){	ipmi_register_watchdog(if_num);}static void ipmi_smi_gone(int if_num){	ipmi_unregister_watchdog(if_num);}static struct ipmi_smi_watcher smi_watcher ={	.owner    = THIS_MODULE,	.new_smi  = ipmi_new_smi,	.smi_gone = ipmi_smi_gone};static int action_op(const char *inval, char *outval){	if (outval)		strcpy(outval, action);	if (!inval)		return 0;	if (strcmp(inval, "reset") == 0)		action_val = WDOG_TIMEOUT_RESET;	else if (strcmp(inval, "none") == 0)		action_val = WDOG_TIMEOUT_NONE;	else if (strcmp(inval, "power_cycle") == 0)		action_val = WDOG_TIMEOUT_POWER_CYCLE;	else if (strcmp(inval, "power_off") == 0)		action_val = WDOG_TIMEOUT_POWER_DOWN;	else		return -EINVAL;	strcpy(action, inval);	return 0;}static int preaction_op(const char *inval, char *outval){	if (outval)		strcpy(outval, preaction);	if (!inval)		return 0;	if (strcmp(inval, "pre_none") == 0)		preaction_val = WDOG_PRETIMEOUT_NONE;	else if (strcmp(inval, "pre_smi") == 0)		preaction_val = WDOG_PRETIMEOUT_SMI;#ifdef HAVE_DIE_NMI	else if (strcmp(inval, "pre_nmi") == 0)		preaction_val = WDOG_PRETIMEOUT_NMI;#endif	else if (strcmp(inval, "pre_int") == 0)		preaction_val = WDOG_PRETIMEOUT_MSG_INT;	else		return -EINVAL;	strcpy(preaction, inval);	return 0;}static int preop_op(const char *inval, char *outval){	if (outval)		strcpy(outval, preop);	if (!inval)		return 0;	if (strcmp(inval, "preop_none") == 0)		preop_val = WDOG_PREOP_NONE;	else if (strcmp(inval, "preop_panic") == 0)		preop_val = WDOG_PREOP_PANIC;	else if (strcmp(inval, "preop_give_data") == 0)		preop_val = WDOG_PREOP_GIVE_DATA;	else		return -EINVAL;	strcpy(preop, inval);	return 0;}static void check_parms(void){#ifdef HAVE_DIE_NMI	int do_nmi = 0;	int rv;	if (preaction_val == WDOG_PRETIMEOUT_NMI) {		do_nmi = 1;		if (preop_val == WDOG_PREOP_GIVE_DATA) {			printk(KERN_WARNING PFX "Pretimeout op is to give data"			       " but NMI pretimeout is enabled, setting"			       " pretimeout op to none\n");			preop_op("preop_none", NULL);			do_nmi = 0;		}	}	if (do_nmi && !nmi_handler_registered) {		rv = register_die_notifier(&ipmi_nmi_handler);		if (rv) {			printk(KERN_WARNING PFX			       "Can't register nmi handler\n");			return;		} else			nmi_handler_registered = 1;	} else if (!do_nmi && nmi_handler_registered) {		unregister_die_notifier(&ipmi_nmi_handler);		nmi_handler_registered = 0;	}#endif}static int __init ipmi_wdog_init(void){	int rv;	if (action_op(action, NULL)) {		action_op("reset", NULL);		printk(KERN_INFO PFX "Unknown action '%s', defaulting to"		       " reset\n", action);	}	if (preaction_op(preaction, NULL)) {		preaction_op("pre_none", NULL);		printk(KERN_INFO PFX "Unknown preaction '%s', defaulting to"		       " none\n", preaction);	}	if (preop_op(preop, NULL)) {		preop_op("preop_none", NULL);		printk(KERN_INFO PFX "Unknown preop '%s', defaulting to"		       " none\n", preop);	}	check_parms();	register_reboot_notifier(&wdog_reboot_notifier);	atomic_notifier_chain_register(&panic_notifier_list,			&wdog_panic_notifier);	rv = ipmi_smi_watcher_register(&smi_watcher);	if (rv) {#ifdef HAVE_DIE_NMI		if (nmi_handler_registered)			unregister_die_notifier(&ipmi_nmi_handler);#endif		atomic_notifier_chain_unregister(&panic_notifier_list,						 &wdog_panic_notifier);		unregister_reboot_notifier(&wdog_reboot_notifier);		printk(KERN_WARNING PFX "can't register smi watcher\n");		return rv;	}	printk(KERN_INFO PFX "driver initialized\n");	return 0;}static void __exit ipmi_wdog_exit(void){	ipmi_smi_watcher_unregister(&smi_watcher);	ipmi_unregister_watchdog(watchdog_ifnum);#ifdef HAVE_DIE_NMI	if (nmi_handler_registered)		unregister_die_notifier(&ipmi_nmi_handler);#endif	atomic_notifier_chain_unregister(&panic_notifier_list,					 &wdog_panic_notifier);	unregister_reboot_notifier(&wdog_reboot_notifier);}module_exit(ipmi_wdog_exit);module_init(ipmi_wdog_init);MODULE_LICENSE("GPL");MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -