ipmi:watchdog: Rework locking and handling
Simplify things by creating one set of message handling data for setting the watchdog and doing a heartbeat. Rework the locking to avoid some (probably not very important) races and to avoid a fairly unlikely infinite recursion. Get rid of ipmi_ignore_heartbeat, it wasn't used, and use watchdog_user to tell if we have a working IPMI device below us. Signed-off-by: Corey Minyard <cminyard@mvista.com>
This commit is contained in:
Родитель
252e30c1e7
Коммит
d1b29b9742
|
@ -153,7 +153,7 @@ static DEFINE_SPINLOCK(ipmi_read_lock);
|
|||
static char data_to_read;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(read_q);
|
||||
static struct fasync_struct *fasync_q;
|
||||
static char pretimeout_since_last_heartbeat;
|
||||
static atomic_t pretimeout_since_last_heartbeat;
|
||||
static char expect_close;
|
||||
|
||||
static int ifnum_to_use = -1;
|
||||
|
@ -303,9 +303,6 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
|
|||
/* Default state of the timer. */
|
||||
static unsigned char ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
|
||||
/* If shutting down via IPMI, we ignore the heartbeat. */
|
||||
static int ipmi_ignore_heartbeat;
|
||||
|
||||
/* Is someone using the watchdog? Only one user is allowed. */
|
||||
static unsigned long ipmi_wdog_open;
|
||||
|
||||
|
@ -329,35 +326,33 @@ static int testing_nmi;
|
|||
static int nmi_handler_registered;
|
||||
#endif
|
||||
|
||||
static int ipmi_heartbeat(void);
|
||||
static int __ipmi_heartbeat(void);
|
||||
|
||||
/*
|
||||
* We use a mutex to make sure that only one thing can send a set
|
||||
* timeout at one time, because we only have one copy of the data.
|
||||
* The mutex is claimed when the set_timeout is sent and freed
|
||||
* when both messages are free.
|
||||
* We use a mutex to make sure that only one thing can send a set a
|
||||
* message at one time. The mutex is claimed when a message is sent
|
||||
* and freed when both the send and receive messages are free.
|
||||
*/
|
||||
static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(set_timeout_lock);
|
||||
static DECLARE_COMPLETION(set_timeout_wait);
|
||||
static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
|
||||
static atomic_t msg_tofree = ATOMIC_INIT(0);
|
||||
static DECLARE_COMPLETION(msg_wait);
|
||||
static void msg_free_smi(struct ipmi_smi_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&set_timeout_tofree))
|
||||
complete(&set_timeout_wait);
|
||||
if (atomic_dec_and_test(&msg_tofree))
|
||||
complete(&msg_wait);
|
||||
}
|
||||
static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
|
||||
static void msg_free_recv(struct ipmi_recv_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&set_timeout_tofree))
|
||||
complete(&set_timeout_wait);
|
||||
if (atomic_dec_and_test(&msg_tofree))
|
||||
complete(&msg_wait);
|
||||
}
|
||||
static struct ipmi_smi_msg set_timeout_smi_msg = {
|
||||
.done = set_timeout_free_smi
|
||||
static struct ipmi_smi_msg smi_msg = {
|
||||
.done = msg_free_smi
|
||||
};
|
||||
static struct ipmi_recv_msg set_timeout_recv_msg = {
|
||||
.done = set_timeout_free_recv
|
||||
static struct ipmi_recv_msg recv_msg = {
|
||||
.done = msg_free_recv
|
||||
};
|
||||
|
||||
static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
||||
static int __ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
||||
struct ipmi_recv_msg *recv_msg,
|
||||
int *send_heartbeat_now)
|
||||
{
|
||||
|
@ -368,9 +363,6 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
|||
int hbnow = 0;
|
||||
|
||||
|
||||
/* These can be cleared as we are setting the timeout. */
|
||||
pretimeout_since_last_heartbeat = 0;
|
||||
|
||||
data[0] = 0;
|
||||
WDOG_SET_TIMER_USE(data[0], WDOG_TIMER_USE_SMS_OS);
|
||||
|
||||
|
@ -414,46 +406,48 @@ static int i_ipmi_set_timeout(struct ipmi_smi_msg *smi_msg,
|
|||
smi_msg,
|
||||
recv_msg,
|
||||
1);
|
||||
if (rv) {
|
||||
printk(KERN_WARNING PFX "set timeout error: %d\n",
|
||||
rv);
|
||||
}
|
||||
if (rv)
|
||||
pr_warn(PFX "set timeout error: %d\n", rv);
|
||||
else if (send_heartbeat_now)
|
||||
*send_heartbeat_now = hbnow;
|
||||
|
||||
if (send_heartbeat_now)
|
||||
*send_heartbeat_now = hbnow;
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _ipmi_set_timeout(int do_heartbeat)
|
||||
{
|
||||
int send_heartbeat_now;
|
||||
int rv;
|
||||
|
||||
if (!watchdog_user)
|
||||
return -ENODEV;
|
||||
|
||||
atomic_set(&msg_tofree, 2);
|
||||
|
||||
rv = __ipmi_set_timeout(&smi_msg,
|
||||
&recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv)
|
||||
return rv;
|
||||
|
||||
wait_for_completion(&msg_wait);
|
||||
|
||||
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|
||||
|| ((send_heartbeat_now)
|
||||
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
|
||||
rv = __ipmi_heartbeat();
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ipmi_set_timeout(int do_heartbeat)
|
||||
{
|
||||
int send_heartbeat_now;
|
||||
int rv;
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
rv = _ipmi_set_timeout(do_heartbeat);
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
|
||||
/* We can only send one of these at a time. */
|
||||
mutex_lock(&set_timeout_lock);
|
||||
|
||||
atomic_set(&set_timeout_tofree, 2);
|
||||
|
||||
rv = i_ipmi_set_timeout(&set_timeout_smi_msg,
|
||||
&set_timeout_recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv) {
|
||||
mutex_unlock(&set_timeout_lock);
|
||||
goto out;
|
||||
}
|
||||
|
||||
wait_for_completion(&set_timeout_wait);
|
||||
|
||||
mutex_unlock(&set_timeout_lock);
|
||||
|
||||
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
|
||||
|| ((send_heartbeat_now)
|
||||
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
|
||||
rv = ipmi_heartbeat();
|
||||
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -531,7 +525,7 @@ static void panic_halt_ipmi_set_timeout(void)
|
|||
while (atomic_read(&panic_done_count) != 0)
|
||||
ipmi_poll_interface(watchdog_user);
|
||||
atomic_add(1, &panic_done_count);
|
||||
rv = i_ipmi_set_timeout(&panic_halt_smi_msg,
|
||||
rv = __ipmi_set_timeout(&panic_halt_smi_msg,
|
||||
&panic_halt_recv_msg,
|
||||
&send_heartbeat_now);
|
||||
if (rv) {
|
||||
|
@ -546,69 +540,22 @@ static void panic_halt_ipmi_set_timeout(void)
|
|||
ipmi_poll_interface(watchdog_user);
|
||||
}
|
||||
|
||||
/*
|
||||
* We use a mutex to make sure that only one thing can send a
|
||||
* heartbeat at one time, because we only have one copy of the data.
|
||||
* The semaphore is claimed when the set_timeout is sent and freed
|
||||
* when both messages are free.
|
||||
*/
|
||||
static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
|
||||
static DEFINE_MUTEX(heartbeat_lock);
|
||||
static DECLARE_COMPLETION(heartbeat_wait);
|
||||
static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
|
||||
static int __ipmi_heartbeat(void)
|
||||
{
|
||||
if (atomic_dec_and_test(&heartbeat_tofree))
|
||||
complete(&heartbeat_wait);
|
||||
}
|
||||
static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
|
||||
{
|
||||
if (atomic_dec_and_test(&heartbeat_tofree))
|
||||
complete(&heartbeat_wait);
|
||||
}
|
||||
static struct ipmi_smi_msg heartbeat_smi_msg = {
|
||||
.done = heartbeat_free_smi
|
||||
};
|
||||
static struct ipmi_recv_msg heartbeat_recv_msg = {
|
||||
.done = heartbeat_free_recv
|
||||
};
|
||||
|
||||
static int ipmi_heartbeat(void)
|
||||
{
|
||||
struct kernel_ipmi_msg msg;
|
||||
int rv;
|
||||
struct kernel_ipmi_msg msg;
|
||||
int rv;
|
||||
struct ipmi_system_interface_addr addr;
|
||||
int timeout_retries = 0;
|
||||
|
||||
if (ipmi_ignore_heartbeat)
|
||||
return 0;
|
||||
|
||||
if (ipmi_start_timer_on_heartbeat) {
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
ipmi_watchdog_state = action_val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
} else if (pretimeout_since_last_heartbeat) {
|
||||
/*
|
||||
* A pretimeout occurred, make sure we set the timeout.
|
||||
* We don't want to set the action, though, we want to
|
||||
* leave that alone (thus it can't be combined with the
|
||||
* above operation.
|
||||
*/
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
}
|
||||
|
||||
mutex_lock(&heartbeat_lock);
|
||||
int timeout_retries = 0;
|
||||
|
||||
restart:
|
||||
atomic_set(&heartbeat_tofree, 2);
|
||||
|
||||
/*
|
||||
* Don't reset the timer if we have the timer turned off, that
|
||||
* re-enables the watchdog.
|
||||
*/
|
||||
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE)
|
||||
return 0;
|
||||
}
|
||||
|
||||
atomic_set(&msg_tofree, 2);
|
||||
|
||||
addr.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
|
||||
addr.channel = IPMI_BMC_CHANNEL;
|
||||
|
@ -623,26 +570,23 @@ restart:
|
|||
0,
|
||||
&msg,
|
||||
NULL,
|
||||
&heartbeat_smi_msg,
|
||||
&heartbeat_recv_msg,
|
||||
&smi_msg,
|
||||
&recv_msg,
|
||||
1);
|
||||
if (rv) {
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
printk(KERN_WARNING PFX "heartbeat failure: %d\n",
|
||||
rv);
|
||||
pr_warn(PFX "heartbeat send failure: %d\n", rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/* Wait for the heartbeat to be sent. */
|
||||
wait_for_completion(&heartbeat_wait);
|
||||
wait_for_completion(&msg_wait);
|
||||
|
||||
if (heartbeat_recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) {
|
||||
if (recv_msg.msg.data[0] == IPMI_WDOG_TIMER_NOT_INIT_RESP) {
|
||||
timeout_retries++;
|
||||
if (timeout_retries > 3) {
|
||||
printk(KERN_ERR PFX ": Unable to restore the IPMI"
|
||||
" watchdog's settings, giving up.\n");
|
||||
pr_err(PFX ": Unable to restore the IPMI watchdog's settings, giving up.\n");
|
||||
rv = -EIO;
|
||||
goto out_unlock;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -651,18 +595,17 @@ restart:
|
|||
* to restore the timer's info. Note that we still hold
|
||||
* the heartbeat lock, to keep a heartbeat from happening
|
||||
* in this process, so must say no heartbeat to avoid a
|
||||
* deadlock on this mutex.
|
||||
* deadlock on this mutex
|
||||
*/
|
||||
rv = ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
if (rv) {
|
||||
printk(KERN_ERR PFX ": Unable to send the command to"
|
||||
" set the watchdog's settings, giving up.\n");
|
||||
goto out_unlock;
|
||||
pr_err(PFX ": Unable to send the command to set the watchdog's settings, giving up.\n");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* We might need a new heartbeat, so do it now */
|
||||
/* Might need a heartbeat send, go ahead and do it. */
|
||||
goto restart;
|
||||
} else if (heartbeat_recv_msg.msg.data[0] != 0) {
|
||||
} else if (recv_msg.msg.data[0] != 0) {
|
||||
/*
|
||||
* Got an error in the heartbeat response. It was already
|
||||
* reported in ipmi_wdog_msg_handler, but we should return
|
||||
|
@ -671,8 +614,43 @@ restart:
|
|||
rv = -EINVAL;
|
||||
}
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&heartbeat_lock);
|
||||
out:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int _ipmi_heartbeat(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
if (!watchdog_user)
|
||||
return -ENODEV;
|
||||
|
||||
if (ipmi_start_timer_on_heartbeat) {
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
ipmi_watchdog_state = action_val;
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
} else if (atomic_cmpxchg(&pretimeout_since_last_heartbeat, 1, 0)) {
|
||||
/*
|
||||
* A pretimeout occurred, make sure we set the timeout.
|
||||
* We don't want to set the action, though, we want to
|
||||
* leave that alone (thus it can't be combined with the
|
||||
* above operation.
|
||||
*/
|
||||
rv = _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
} else {
|
||||
rv = __ipmi_heartbeat();
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int ipmi_heartbeat(void)
|
||||
{
|
||||
int rv;
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
rv = _ipmi_heartbeat();
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
@ -700,7 +678,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
if (i)
|
||||
return -EFAULT;
|
||||
timeout = val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
return _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
|
||||
case WDIOC_GETTIMEOUT:
|
||||
i = copy_to_user(argp, &timeout, sizeof(timeout));
|
||||
|
@ -713,7 +691,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
if (i)
|
||||
return -EFAULT;
|
||||
pretimeout = val;
|
||||
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
return _ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
|
||||
|
||||
case WDIOC_GETPRETIMEOUT:
|
||||
i = copy_to_user(argp, &pretimeout, sizeof(pretimeout));
|
||||
|
@ -722,7 +700,7 @@ static int ipmi_ioctl(struct file *file,
|
|||
return 0;
|
||||
|
||||
case WDIOC_KEEPALIVE:
|
||||
return ipmi_heartbeat();
|
||||
return _ipmi_heartbeat();
|
||||
|
||||
case WDIOC_SETOPTIONS:
|
||||
i = copy_from_user(&val, argp, sizeof(int));
|
||||
|
@ -730,13 +708,13 @@ static int ipmi_ioctl(struct file *file,
|
|||
return -EFAULT;
|
||||
if (val & WDIOS_DISABLECARD) {
|
||||
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
ipmi_start_timer_on_heartbeat = 0;
|
||||
}
|
||||
|
||||
if (val & WDIOS_ENABLECARD) {
|
||||
ipmi_watchdog_state = action_val;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_FORCE_HB);
|
||||
}
|
||||
return 0;
|
||||
|
||||
|
@ -810,7 +788,7 @@ static ssize_t ipmi_read(struct file *file,
|
|||
* Reading returns if the pretimeout has gone off, and it only does
|
||||
* it once per pretimeout.
|
||||
*/
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
if (!data_to_read) {
|
||||
if (file->f_flags & O_NONBLOCK) {
|
||||
rv = -EAGAIN;
|
||||
|
@ -821,9 +799,9 @@ static ssize_t ipmi_read(struct file *file,
|
|||
add_wait_queue(&read_q, &wait);
|
||||
while (!data_to_read) {
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
schedule();
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
}
|
||||
remove_wait_queue(&read_q, &wait);
|
||||
|
||||
|
@ -835,7 +813,7 @@ static ssize_t ipmi_read(struct file *file,
|
|||
data_to_read = 0;
|
||||
|
||||
out:
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
|
||||
if (rv == 0) {
|
||||
if (copy_to_user(buf, &data_to_read, 1))
|
||||
|
@ -873,10 +851,10 @@ static __poll_t ipmi_poll(struct file *file, poll_table *wait)
|
|||
|
||||
poll_wait(file, &read_q, wait);
|
||||
|
||||
spin_lock(&ipmi_read_lock);
|
||||
spin_lock_irq(&ipmi_read_lock);
|
||||
if (data_to_read)
|
||||
mask |= (EPOLLIN | EPOLLRDNORM);
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irq(&ipmi_read_lock);
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
@ -894,8 +872,10 @@ static int ipmi_close(struct inode *ino, struct file *filep)
|
|||
{
|
||||
if (iminor(ino) == WATCHDOG_MINOR) {
|
||||
if (expect_close == 42) {
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
ipmi_watchdog_state = WDOG_TIMEOUT_NONE;
|
||||
ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
_ipmi_set_timeout(IPMI_SET_TIMEOUT_NO_HB);
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
} else {
|
||||
printk(KERN_CRIT PFX
|
||||
"Unexpected close, not stopping watchdog!\n");
|
||||
|
@ -950,12 +930,13 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data)
|
|||
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);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&ipmi_read_lock, flags);
|
||||
data_to_read = 1;
|
||||
wake_up_interruptible(&read_q);
|
||||
kill_fasync(&fasync_q, SIGIO, POLL_IN);
|
||||
|
||||
spin_unlock(&ipmi_read_lock);
|
||||
spin_unlock_irqrestore(&ipmi_read_lock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -963,7 +944,7 @@ static void ipmi_wdog_pretimeout_handler(void *handler_data)
|
|||
* 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;
|
||||
atomic_set(&pretimeout_since_last_heartbeat, 1);
|
||||
}
|
||||
|
||||
static const struct ipmi_user_hndl ipmi_hndlrs = {
|
||||
|
@ -1063,34 +1044,38 @@ static void ipmi_register_watchdog(int ipmi_intf)
|
|||
static void ipmi_unregister_watchdog(int ipmi_intf)
|
||||
{
|
||||
int rv;
|
||||
ipmi_user_t loc_user = watchdog_user;
|
||||
|
||||
if (!watchdog_user)
|
||||
goto out;
|
||||
if (!loc_user)
|
||||
return;
|
||||
|
||||
if (watchdog_ifnum != ipmi_intf)
|
||||
goto out;
|
||||
return;
|
||||
|
||||
/* Make sure no one can call us any more. */
|
||||
misc_deregister(&ipmi_wdog_miscdev);
|
||||
|
||||
watchdog_user = NULL;
|
||||
|
||||
/*
|
||||
* 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);
|
||||
while (atomic_read(&msg_tofree))
|
||||
msg_free_smi(NULL);
|
||||
|
||||
mutex_lock(&ipmi_watchdog_mutex);
|
||||
|
||||
/* 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;
|
||||
rv = ipmi_destroy_user(loc_user);
|
||||
if (rv)
|
||||
pr_warn(PFX "error unlinking from IPMI: %d\n", rv);
|
||||
|
||||
out:
|
||||
return;
|
||||
/* If it comes back, restart it properly. */
|
||||
ipmi_start_timer_on_heartbeat = 1;
|
||||
|
||||
mutex_unlock(&ipmi_watchdog_mutex);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DIE_NMI
|
||||
|
@ -1124,7 +1109,7 @@ ipmi_nmi(unsigned int val, struct pt_regs *regs)
|
|||
/* 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;
|
||||
atomic_set(&pretimeout_since_last_heartbeat, 1);
|
||||
if (atomic_inc_and_test(&preop_panic_excl))
|
||||
nmi_panic(regs, PFX "pre-timeout");
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче