Commit d6dfd131 authored by Corey Minyard's avatar Corey Minyard Committed by Linus Torvalds

[PATCH] IPMI: convert from semaphores to mutexes

Convert the remaining semaphores to mutexes in the IPMI driver.  The
watchdog was using a semaphore as a real semaphore (for IPC), so the
conversion there required adding a completion.
Signed-off-by: default avatarCorey Minyard <minyard@acm.org>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 8a3628d5
...@@ -42,7 +42,7 @@ ...@@ -42,7 +42,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/devfs_fs_kernel.h> #include <linux/devfs_fs_kernel.h>
#include <linux/ipmi.h> #include <linux/ipmi.h>
#include <asm/semaphore.h> #include <linux/mutex.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/compat.h> #include <linux/compat.h>
...@@ -55,7 +55,7 @@ struct ipmi_file_private ...@@ -55,7 +55,7 @@ struct ipmi_file_private
struct file *file; struct file *file;
struct fasync_struct *fasync_queue; struct fasync_struct *fasync_queue;
wait_queue_head_t wait; wait_queue_head_t wait;
struct semaphore recv_sem; struct mutex recv_mutex;
int default_retries; int default_retries;
unsigned int default_retry_time_ms; unsigned int default_retry_time_ms;
}; };
...@@ -141,7 +141,7 @@ static int ipmi_open(struct inode *inode, struct file *file) ...@@ -141,7 +141,7 @@ static int ipmi_open(struct inode *inode, struct file *file)
INIT_LIST_HEAD(&(priv->recv_msgs)); INIT_LIST_HEAD(&(priv->recv_msgs));
init_waitqueue_head(&priv->wait); init_waitqueue_head(&priv->wait);
priv->fasync_queue = NULL; priv->fasync_queue = NULL;
sema_init(&(priv->recv_sem), 1); mutex_init(&priv->recv_mutex);
/* Use the low-level defaults. */ /* Use the low-level defaults. */
priv->default_retries = -1; priv->default_retries = -1;
...@@ -285,15 +285,15 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -285,15 +285,15 @@ static int ipmi_ioctl(struct inode *inode,
break; break;
} }
/* We claim a semaphore because we don't want two /* We claim a mutex because we don't want two
users getting something from the queue at a time. users getting something from the queue at a time.
Since we have to release the spinlock before we can Since we have to release the spinlock before we can
copy the data to the user, it's possible another copy the data to the user, it's possible another
user will grab something from the queue, too. Then user will grab something from the queue, too. Then
the messages might get out of order if something the messages might get out of order if something
fails and the message gets put back onto the fails and the message gets put back onto the
queue. This semaphore prevents that problem. */ queue. This mutex prevents that problem. */
down(&(priv->recv_sem)); mutex_lock(&priv->recv_mutex);
/* Grab the message off the list. */ /* Grab the message off the list. */
spin_lock_irqsave(&(priv->recv_msg_lock), flags); spin_lock_irqsave(&(priv->recv_msg_lock), flags);
...@@ -352,7 +352,7 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -352,7 +352,7 @@ static int ipmi_ioctl(struct inode *inode,
goto recv_putback_on_err; goto recv_putback_on_err;
} }
up(&(priv->recv_sem)); mutex_unlock(&priv->recv_mutex);
ipmi_free_recv_msg(msg); ipmi_free_recv_msg(msg);
break; break;
...@@ -362,11 +362,11 @@ static int ipmi_ioctl(struct inode *inode, ...@@ -362,11 +362,11 @@ static int ipmi_ioctl(struct inode *inode,
spin_lock_irqsave(&(priv->recv_msg_lock), flags); spin_lock_irqsave(&(priv->recv_msg_lock), flags);
list_add(entry, &(priv->recv_msgs)); list_add(entry, &(priv->recv_msgs));
spin_unlock_irqrestore(&(priv->recv_msg_lock), flags); spin_unlock_irqrestore(&(priv->recv_msg_lock), flags);
up(&(priv->recv_sem)); mutex_unlock(&priv->recv_mutex);
break; break;
recv_err: recv_err:
up(&(priv->recv_sem)); mutex_unlock(&priv->recv_mutex);
break; break;
} }
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ipmi.h> #include <linux/ipmi.h>
#include <linux/ipmi_smi.h> #include <linux/ipmi_smi.h>
...@@ -234,7 +235,7 @@ struct ipmi_smi ...@@ -234,7 +235,7 @@ struct ipmi_smi
/* The list of command receivers that are registered for commands /* The list of command receivers that are registered for commands
on this interface. */ on this interface. */
struct semaphore cmd_rcvrs_lock; struct mutex cmd_rcvrs_mutex;
struct list_head cmd_rcvrs; struct list_head cmd_rcvrs;
/* Events that were queues because no one was there to receive /* Events that were queues because no one was there to receive
...@@ -387,10 +388,10 @@ static void clean_up_interface_data(ipmi_smi_t intf) ...@@ -387,10 +388,10 @@ static void clean_up_interface_data(ipmi_smi_t intf)
/* Wholesale remove all the entries from the list in the /* Wholesale remove all the entries from the list in the
* interface and wait for RCU to know that none are in use. */ * interface and wait for RCU to know that none are in use. */
down(&intf->cmd_rcvrs_lock); mutex_lock(&intf->cmd_rcvrs_mutex);
list_add_rcu(&list, &intf->cmd_rcvrs); list_add_rcu(&list, &intf->cmd_rcvrs);
list_del_rcu(&intf->cmd_rcvrs); list_del_rcu(&intf->cmd_rcvrs);
up(&intf->cmd_rcvrs_lock); mutex_unlock(&intf->cmd_rcvrs_mutex);
synchronize_rcu(); synchronize_rcu();
list_for_each_entry_safe(rcvr, rcvr2, &list, link) list_for_each_entry_safe(rcvr, rcvr2, &list, link)
...@@ -846,7 +847,7 @@ int ipmi_destroy_user(ipmi_user_t user) ...@@ -846,7 +847,7 @@ int ipmi_destroy_user(ipmi_user_t user)
* since other things may be using it till we do * since other things may be using it till we do
* synchronize_rcu()) then free everything in that list. * synchronize_rcu()) then free everything in that list.
*/ */
down(&intf->cmd_rcvrs_lock); mutex_lock(&intf->cmd_rcvrs_mutex);
list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) { list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
if (rcvr->user == user) { if (rcvr->user == user) {
list_del_rcu(&rcvr->link); list_del_rcu(&rcvr->link);
...@@ -854,7 +855,7 @@ int ipmi_destroy_user(ipmi_user_t user) ...@@ -854,7 +855,7 @@ int ipmi_destroy_user(ipmi_user_t user)
rcvrs = rcvr; rcvrs = rcvr;
} }
} }
up(&intf->cmd_rcvrs_lock); mutex_unlock(&intf->cmd_rcvrs_mutex);
synchronize_rcu(); synchronize_rcu();
while (rcvrs) { while (rcvrs) {
rcvr = rcvrs; rcvr = rcvrs;
...@@ -984,7 +985,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, ...@@ -984,7 +985,7 @@ int ipmi_register_for_cmd(ipmi_user_t user,
rcvr->netfn = netfn; rcvr->netfn = netfn;
rcvr->user = user; rcvr->user = user;
down(&intf->cmd_rcvrs_lock); mutex_lock(&intf->cmd_rcvrs_mutex);
/* Make sure the command/netfn is not already registered. */ /* Make sure the command/netfn is not already registered. */
entry = find_cmd_rcvr(intf, netfn, cmd); entry = find_cmd_rcvr(intf, netfn, cmd);
if (entry) { if (entry) {
...@@ -995,7 +996,7 @@ int ipmi_register_for_cmd(ipmi_user_t user, ...@@ -995,7 +996,7 @@ int ipmi_register_for_cmd(ipmi_user_t user,
list_add_rcu(&rcvr->link, &intf->cmd_rcvrs); list_add_rcu(&rcvr->link, &intf->cmd_rcvrs);
out_unlock: out_unlock:
up(&intf->cmd_rcvrs_lock); mutex_unlock(&intf->cmd_rcvrs_mutex);
if (rv) if (rv)
kfree(rcvr); kfree(rcvr);
...@@ -1009,17 +1010,17 @@ int ipmi_unregister_for_cmd(ipmi_user_t user, ...@@ -1009,17 +1010,17 @@ int ipmi_unregister_for_cmd(ipmi_user_t user,
ipmi_smi_t intf = user->intf; ipmi_smi_t intf = user->intf;
struct cmd_rcvr *rcvr; struct cmd_rcvr *rcvr;
down(&intf->cmd_rcvrs_lock); mutex_lock(&intf->cmd_rcvrs_mutex);
/* Make sure the command/netfn is not already registered. */ /* Make sure the command/netfn is not already registered. */
rcvr = find_cmd_rcvr(intf, netfn, cmd); rcvr = find_cmd_rcvr(intf, netfn, cmd);
if ((rcvr) && (rcvr->user == user)) { if ((rcvr) && (rcvr->user == user)) {
list_del_rcu(&rcvr->link); list_del_rcu(&rcvr->link);
up(&intf->cmd_rcvrs_lock); mutex_unlock(&intf->cmd_rcvrs_mutex);
synchronize_rcu(); synchronize_rcu();
kfree(rcvr); kfree(rcvr);
return 0; return 0;
} else { } else {
up(&intf->cmd_rcvrs_lock); mutex_unlock(&intf->cmd_rcvrs_mutex);
return -ENOENT; return -ENOENT;
} }
} }
...@@ -2365,7 +2366,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers, ...@@ -2365,7 +2366,7 @@ int ipmi_register_smi(struct ipmi_smi_handlers *handlers,
spin_lock_init(&intf->events_lock); spin_lock_init(&intf->events_lock);
INIT_LIST_HEAD(&intf->waiting_events); INIT_LIST_HEAD(&intf->waiting_events);
intf->waiting_events_count = 0; intf->waiting_events_count = 0;
init_MUTEX(&intf->cmd_rcvrs_lock); mutex_init(&intf->cmd_rcvrs_mutex);
INIT_LIST_HEAD(&intf->cmd_rcvrs); INIT_LIST_HEAD(&intf->cmd_rcvrs);
init_waitqueue_head(&intf->waitq); init_waitqueue_head(&intf->waitq);
......
...@@ -1014,7 +1014,7 @@ static struct ipmi_smi_handlers handlers = ...@@ -1014,7 +1014,7 @@ static struct ipmi_smi_handlers handlers =
#define SI_MAX_PARMS 4 #define SI_MAX_PARMS 4
static LIST_HEAD(smi_infos); static LIST_HEAD(smi_infos);
static DECLARE_MUTEX(smi_infos_lock); static DEFINE_MUTEX(smi_infos_lock);
static int smi_num; /* Used to sequence the SMIs */ static int smi_num; /* Used to sequence the SMIs */
#define DEFAULT_REGSPACING 1 #define DEFAULT_REGSPACING 1
...@@ -2276,7 +2276,7 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2276,7 +2276,7 @@ static int try_smi_init(struct smi_info *new_smi)
new_smi->slave_addr, new_smi->irq); new_smi->slave_addr, new_smi->irq);
} }
down(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (!is_new_interface(new_smi)) { if (!is_new_interface(new_smi)) {
printk(KERN_WARNING "ipmi_si: duplicate interface\n"); printk(KERN_WARNING "ipmi_si: duplicate interface\n");
rv = -EBUSY; rv = -EBUSY;
...@@ -2432,7 +2432,7 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2432,7 +2432,7 @@ static int try_smi_init(struct smi_info *new_smi)
list_add_tail(&new_smi->link, &smi_infos); list_add_tail(&new_smi->link, &smi_infos);
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]);
...@@ -2469,7 +2469,7 @@ static int try_smi_init(struct smi_info *new_smi) ...@@ -2469,7 +2469,7 @@ static int try_smi_init(struct smi_info *new_smi)
kfree(new_smi); kfree(new_smi);
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
return rv; return rv;
} }
...@@ -2527,26 +2527,26 @@ static __devinit int init_ipmi_si(void) ...@@ -2527,26 +2527,26 @@ static __devinit int init_ipmi_si(void)
#endif #endif
if (si_trydefaults) { if (si_trydefaults) {
down(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (list_empty(&smi_infos)) { if (list_empty(&smi_infos)) {
/* No BMC was found, try defaults. */ /* No BMC was found, try defaults. */
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
default_find_bmc(); default_find_bmc();
} else { } else {
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
} }
} }
down(&smi_infos_lock); mutex_lock(&smi_infos_lock);
if (list_empty(&smi_infos)) { if (list_empty(&smi_infos)) {
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
pci_unregister_driver(&ipmi_pci_driver); pci_unregister_driver(&ipmi_pci_driver);
#endif #endif
printk("ipmi_si: Unable to find any System Interface(s)\n"); printk("ipmi_si: Unable to find any System Interface(s)\n");
return -ENODEV; return -ENODEV;
} else { } else {
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
return 0; return 0;
} }
} }
...@@ -2622,10 +2622,10 @@ static __exit void cleanup_ipmi_si(void) ...@@ -2622,10 +2622,10 @@ static __exit void cleanup_ipmi_si(void)
pci_unregister_driver(&ipmi_pci_driver); pci_unregister_driver(&ipmi_pci_driver);
#endif #endif
down(&smi_infos_lock); mutex_lock(&smi_infos_lock);
list_for_each_entry_safe(e, tmp_e, &smi_infos, link) list_for_each_entry_safe(e, tmp_e, &smi_infos, link)
cleanup_one_si(e); cleanup_one_si(e);
up(&smi_infos_lock); mutex_unlock(&smi_infos_lock);
driver_unregister(&ipmi_driver); driver_unregister(&ipmi_driver);
} }
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
#include <linux/watchdog.h> #include <linux/watchdog.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/completion.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -303,21 +304,22 @@ static int ipmi_heartbeat(void); ...@@ -303,21 +304,22 @@ static int ipmi_heartbeat(void);
static void panic_halt_ipmi_heartbeat(void); static void panic_halt_ipmi_heartbeat(void);
/* We use a semaphore to make sure that only one thing can send a set /* 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. timeout at one time, because we only have one copy of the data.
The semaphore is claimed when the set_timeout is sent and freed The mutex is claimed when the set_timeout is sent and freed
when both messages are free. */ when both messages are free. */
static atomic_t set_timeout_tofree = ATOMIC_INIT(0); static atomic_t set_timeout_tofree = ATOMIC_INIT(0);
static DECLARE_MUTEX(set_timeout_lock); static DEFINE_MUTEX(set_timeout_lock);
static DECLARE_COMPLETION(set_timeout_wait);
static void set_timeout_free_smi(struct ipmi_smi_msg *msg) static void set_timeout_free_smi(struct ipmi_smi_msg *msg)
{ {
if (atomic_dec_and_test(&set_timeout_tofree)) if (atomic_dec_and_test(&set_timeout_tofree))
up(&set_timeout_lock); complete(&set_timeout_wait);
} }
static void set_timeout_free_recv(struct ipmi_recv_msg *msg) static void set_timeout_free_recv(struct ipmi_recv_msg *msg)
{ {
if (atomic_dec_and_test(&set_timeout_tofree)) if (atomic_dec_and_test(&set_timeout_tofree))
up(&set_timeout_lock); complete(&set_timeout_wait);
} }
static struct ipmi_smi_msg set_timeout_smi_msg = static struct ipmi_smi_msg set_timeout_smi_msg =
{ {
...@@ -399,7 +401,7 @@ static int ipmi_set_timeout(int do_heartbeat) ...@@ -399,7 +401,7 @@ static int ipmi_set_timeout(int do_heartbeat)
/* We can only send one of these at a time. */ /* We can only send one of these at a time. */
down(&set_timeout_lock); mutex_lock(&set_timeout_lock);
atomic_set(&set_timeout_tofree, 2); atomic_set(&set_timeout_tofree, 2);
...@@ -407,16 +409,21 @@ static int ipmi_set_timeout(int do_heartbeat) ...@@ -407,16 +409,21 @@ static int ipmi_set_timeout(int do_heartbeat)
&set_timeout_recv_msg, &set_timeout_recv_msg,
&send_heartbeat_now); &send_heartbeat_now);
if (rv) { if (rv) {
up(&set_timeout_lock); mutex_unlock(&set_timeout_lock);
} else { goto out;
if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB) }
|| ((send_heartbeat_now)
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY))) wait_for_completion(&set_timeout_wait);
{
rv = ipmi_heartbeat(); if ((do_heartbeat == IPMI_SET_TIMEOUT_FORCE_HB)
} || ((send_heartbeat_now)
&& (do_heartbeat == IPMI_SET_TIMEOUT_HB_IF_NECESSARY)))
{
rv = ipmi_heartbeat();
} }
mutex_unlock(&set_timeout_lock);
out:
return rv; return rv;
} }
...@@ -458,17 +465,17 @@ static void panic_halt_ipmi_set_timeout(void) ...@@ -458,17 +465,17 @@ static void panic_halt_ipmi_set_timeout(void)
The semaphore is claimed when the set_timeout is sent and freed The semaphore is claimed when the set_timeout is sent and freed
when both messages are free. */ when both messages are free. */
static atomic_t heartbeat_tofree = ATOMIC_INIT(0); static atomic_t heartbeat_tofree = ATOMIC_INIT(0);
static DECLARE_MUTEX(heartbeat_lock); static DEFINE_MUTEX(heartbeat_lock);
static DECLARE_MUTEX_LOCKED(heartbeat_wait_lock); static DECLARE_COMPLETION(heartbeat_wait);
static void heartbeat_free_smi(struct ipmi_smi_msg *msg) static void heartbeat_free_smi(struct ipmi_smi_msg *msg)
{ {
if (atomic_dec_and_test(&heartbeat_tofree)) if (atomic_dec_and_test(&heartbeat_tofree))
up(&heartbeat_wait_lock); complete(&heartbeat_wait);
} }
static void heartbeat_free_recv(struct ipmi_recv_msg *msg) static void heartbeat_free_recv(struct ipmi_recv_msg *msg)
{ {
if (atomic_dec_and_test(&heartbeat_tofree)) if (atomic_dec_and_test(&heartbeat_tofree))
up(&heartbeat_wait_lock); complete(&heartbeat_wait);
} }
static struct ipmi_smi_msg heartbeat_smi_msg = static struct ipmi_smi_msg heartbeat_smi_msg =
{ {
...@@ -511,14 +518,14 @@ static int ipmi_heartbeat(void) ...@@ -511,14 +518,14 @@ static int ipmi_heartbeat(void)
return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY); return ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
} }
down(&heartbeat_lock); mutex_lock(&heartbeat_lock);
atomic_set(&heartbeat_tofree, 2); atomic_set(&heartbeat_tofree, 2);
/* Don't reset the timer if we have the timer turned off, that /* Don't reset the timer if we have the timer turned off, that
re-enables the watchdog. */ re-enables the watchdog. */
if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) { if (ipmi_watchdog_state == WDOG_TIMEOUT_NONE) {
up(&heartbeat_lock); mutex_unlock(&heartbeat_lock);
return 0; return 0;
} }
...@@ -539,14 +546,14 @@ static int ipmi_heartbeat(void) ...@@ -539,14 +546,14 @@ static int ipmi_heartbeat(void)
&heartbeat_recv_msg, &heartbeat_recv_msg,
1); 1);
if (rv) { if (rv) {
up(&heartbeat_lock); mutex_unlock(&heartbeat_lock);
printk(KERN_WARNING PFX "heartbeat failure: %d\n", printk(KERN_WARNING PFX "heartbeat failure: %d\n",
rv); rv);
return rv; return rv;
} }
/* Wait for the heartbeat to be sent. */ /* Wait for the heartbeat to be sent. */
down(&heartbeat_wait_lock); wait_for_completion(&heartbeat_wait);
if (heartbeat_recv_msg.msg.data[0] != 0) { if (heartbeat_recv_msg.msg.data[0] != 0) {
/* Got an error in the heartbeat response. It was already /* Got an error in the heartbeat response. It was already
...@@ -555,7 +562,7 @@ static int ipmi_heartbeat(void) ...@@ -555,7 +562,7 @@ static int ipmi_heartbeat(void)
rv = -EINVAL; rv = -EINVAL;
} }
up(&heartbeat_lock); mutex_unlock(&heartbeat_lock);
return rv; return rv;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment