Skip to content

Commit

Permalink
Staging: batman-adv: Limit spin_locks to spin_lock_bh
Browse files Browse the repository at this point in the history
spin_lock_irqsave disables the IRQs and stores them inside the flags
provided by the caller. This is needed to protect a bottom half handler
or a user context critical section from being interrupted by an
interrupt handler which also tries to acquire the spinlock and locks
forever.

The linux device drivers will receive the packets inside an interrupt
handler and the network infrastructure will process them inside bottom
half. Thus batman-adv will only run in user context and bottom half
handlers. We can conclude that batman-adv doesn't share its own
spinlocks with real interrupt handlers.

This makes it possible to exchange the quite complex spin_lock_irqsave
with spin_lock_bh which only stops bottom halves from running on the
current cpu, but allows interrupt handlers to take over to keep the
interrupt latency low.

Signed-off-by: Sven Eckelmann <sven.eckelmann@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
  • Loading branch information
Sven Eckelmann authored and Greg Kroah-Hartman committed Nov 29, 2010
1 parent bd20495 commit 7a18deb
Show file tree
Hide file tree
Showing 10 changed files with 147 additions and 203 deletions.
12 changes: 5 additions & 7 deletions drivers/staging/batman-adv/aggregation.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,6 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
{
struct bat_priv *bat_priv = netdev_priv(if_incoming->soft_iface);
struct forw_packet *forw_packet_aggr;
unsigned long flags;
unsigned char *skb_buff;

/* own packet should always be scheduled */
Expand Down Expand Up @@ -156,9 +155,9 @@ static void new_aggregated_packet(unsigned char *packet_buff, int packet_len,
forw_packet_aggr->direct_link_flags |= 1;

/* add new packet to packet list */
spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
spin_lock_bh(&bat_priv->forw_bat_list_lock);
hlist_add_head(&forw_packet_aggr->list, &bat_priv->forw_bat_list);
spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
spin_unlock_bh(&bat_priv->forw_bat_list_lock);

/* start timer for this packet */
INIT_DELAYED_WORK(&forw_packet_aggr->delayed_work,
Expand Down Expand Up @@ -201,10 +200,9 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
struct batman_packet *batman_packet =
(struct batman_packet *)packet_buff;
bool direct_link = batman_packet->flags & DIRECTLINK ? 1 : 0;
unsigned long flags;

/* find position for the packet in the forward queue */
spin_lock_irqsave(&bat_priv->forw_bat_list_lock, flags);
spin_lock_bh(&bat_priv->forw_bat_list_lock);
/* own packets are not to be aggregated */
if ((atomic_read(&bat_priv->aggregated_ogms)) && (!own_packet)) {
hlist_for_each_entry(forw_packet_pos, tmp_node,
Expand All @@ -225,7 +223,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
* suitable aggregation packet found */
if (forw_packet_aggr == NULL) {
/* the following section can run without the lock */
spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
spin_unlock_bh(&bat_priv->forw_bat_list_lock);

/**
* if we could not aggregate this packet with one of the others
Expand All @@ -243,7 +241,7 @@ void add_bat_packet_to_list(struct bat_priv *bat_priv,
aggregate(forw_packet_aggr,
packet_buff, packet_len,
direct_link);
spin_unlock_irqrestore(&bat_priv->forw_bat_list_lock, flags);
spin_unlock_bh(&bat_priv->forw_bat_list_lock);
}
}

Expand Down
14 changes: 6 additions & 8 deletions drivers/staging/batman-adv/bat_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,11 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
va_list args;
static char debug_log_buf[256];
char *p;
unsigned long flags;

if (!debug_log)
return 0;

spin_lock_irqsave(&debug_log->lock, flags);
spin_lock_bh(&debug_log->lock);
va_start(args, fmt);
printed_len = vscnprintf(debug_log_buf, sizeof(debug_log_buf),
fmt, args);
Expand All @@ -68,7 +67,7 @@ static int fdebug_log(struct debug_log *debug_log, char *fmt, ...)
for (p = debug_log_buf; *p != 0; p++)
emit_log_char(debug_log, *p);

spin_unlock_irqrestore(&debug_log->lock, flags);
spin_unlock_bh(&debug_log->lock);

wake_up(&debug_log->queue_wait);

Expand Down Expand Up @@ -110,7 +109,6 @@ static ssize_t log_read(struct file *file, char __user *buf,
struct debug_log *debug_log = bat_priv->debug_log;
int error, i = 0;
char c;
unsigned long flags;

if ((file->f_flags & O_NONBLOCK) &&
!(debug_log->log_end - debug_log->log_start))
Expand All @@ -131,26 +129,26 @@ static ssize_t log_read(struct file *file, char __user *buf,
if (error)
return error;

spin_lock_irqsave(&debug_log->lock, flags);
spin_lock_bh(&debug_log->lock);

while ((!error) && (i < count) &&
(debug_log->log_start != debug_log->log_end)) {
c = LOG_BUFF(debug_log->log_start);

debug_log->log_start++;

spin_unlock_irqrestore(&debug_log->lock, flags);
spin_unlock_bh(&debug_log->lock);

error = __put_user(c, buf);

spin_lock_irqsave(&debug_log->lock, flags);
spin_lock_bh(&debug_log->lock);

buf++;
i++;

}

spin_unlock_irqrestore(&debug_log->lock, flags);
spin_unlock_bh(&debug_log->lock);

if (!error)
return i;
Expand Down
24 changes: 10 additions & 14 deletions drivers/staging/batman-adv/icmp_socket.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,8 @@ static int bat_socket_release(struct inode *inode, struct file *file)
struct socket_client *socket_client = file->private_data;
struct socket_packet *socket_packet;
struct list_head *list_pos, *list_pos_tmp;
unsigned long flags;

spin_lock_irqsave(&socket_client->lock, flags);
spin_lock_bh(&socket_client->lock);

/* for all packets in the queue ... */
list_for_each_safe(list_pos, list_pos_tmp, &socket_client->queue_list) {
Expand All @@ -99,7 +98,7 @@ static int bat_socket_release(struct inode *inode, struct file *file)
}

socket_client_hash[socket_client->index] = NULL;
spin_unlock_irqrestore(&socket_client->lock, flags);
spin_unlock_bh(&socket_client->lock);

kfree(socket_client);
dec_module_count();
Expand All @@ -114,7 +113,6 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
struct socket_packet *socket_packet;
size_t packet_len;
int error;
unsigned long flags;

if ((file->f_flags & O_NONBLOCK) && (socket_client->queue_len == 0))
return -EAGAIN;
Expand All @@ -131,14 +129,14 @@ static ssize_t bat_socket_read(struct file *file, char __user *buf,
if (error)
return error;

spin_lock_irqsave(&socket_client->lock, flags);
spin_lock_bh(&socket_client->lock);

socket_packet = list_first_entry(&socket_client->queue_list,
struct socket_packet, list);
list_del(&socket_packet->list);
socket_client->queue_len--;

spin_unlock_irqrestore(&socket_client->lock, flags);
spin_unlock_bh(&socket_client->lock);

error = __copy_to_user(buf, &socket_packet->icmp_packet,
socket_packet->icmp_len);
Expand All @@ -164,7 +162,6 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
struct batman_if *batman_if;
size_t packet_len = sizeof(struct icmp_packet);
uint8_t dstaddr[ETH_ALEN];
unsigned long flags;

if (len < sizeof(struct icmp_packet)) {
bat_dbg(DBG_BATMAN, bat_priv,
Expand Down Expand Up @@ -224,7 +221,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
if (atomic_read(&bat_priv->mesh_state) != MESH_ACTIVE)
goto dst_unreach;

spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);
orig_node = ((struct orig_node *)hash_find(bat_priv->orig_hash,
compare_orig, choose_orig,
icmp_packet->dst));
Expand All @@ -238,7 +235,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
batman_if = orig_node->router->if_incoming;
memcpy(dstaddr, orig_node->router->addr, ETH_ALEN);

spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);

if (!batman_if)
goto dst_unreach;
Expand All @@ -258,7 +255,7 @@ static ssize_t bat_socket_write(struct file *file, const char __user *buff,
goto out;

unlock:
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
dst_unreach:
icmp_packet->msg_type = DESTINATION_UNREACHABLE;
bat_socket_add_packet(socket_client, icmp_packet, packet_len);
Expand Down Expand Up @@ -313,7 +310,6 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
size_t icmp_len)
{
struct socket_packet *socket_packet;
unsigned long flags;

socket_packet = kmalloc(sizeof(struct socket_packet), GFP_ATOMIC);

Expand All @@ -324,12 +320,12 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
memcpy(&socket_packet->icmp_packet, icmp_packet, icmp_len);
socket_packet->icmp_len = icmp_len;

spin_lock_irqsave(&socket_client->lock, flags);
spin_lock_bh(&socket_client->lock);

/* while waiting for the lock the socket_client could have been
* deleted */
if (!socket_client_hash[icmp_packet->uid]) {
spin_unlock_irqrestore(&socket_client->lock, flags);
spin_unlock_bh(&socket_client->lock);
kfree(socket_packet);
return;
}
Expand All @@ -346,7 +342,7 @@ static void bat_socket_add_packet(struct socket_client *socket_client,
socket_client->queue_len--;
}

spin_unlock_irqrestore(&socket_client->lock, flags);
spin_unlock_bh(&socket_client->lock);

wake_up(&socket_client->queue_wait);
}
Expand Down
37 changes: 15 additions & 22 deletions drivers/staging/batman-adv/originator.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,21 @@ static void start_purge_timer(struct bat_priv *bat_priv)

int originator_init(struct bat_priv *bat_priv)
{
unsigned long flags;
if (bat_priv->orig_hash)
return 1;

spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);
bat_priv->orig_hash = hash_new(128);

if (!bat_priv->orig_hash)
goto err;

spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
start_purge_timer(bat_priv);
return 1;

err:
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
return 0;
}

Expand Down Expand Up @@ -108,17 +107,15 @@ static void free_orig_node(void *data, void *arg)

void originator_free(struct bat_priv *bat_priv)
{
unsigned long flags;

if (!bat_priv->orig_hash)
return;

cancel_delayed_work_sync(&bat_priv->orig_work);

spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);
hash_delete(bat_priv->orig_hash, free_orig_node, bat_priv);
bat_priv->orig_hash = NULL;
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
}

/* this function finds or creates an originator entry for the given
Expand Down Expand Up @@ -273,9 +270,8 @@ static void _purge_orig(struct bat_priv *bat_priv)
HASHIT(hashit);
struct element_t *bucket;
struct orig_node *orig_node;
unsigned long flags;

spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);

/* for all origins... */
while (hash_iterate(bat_priv->orig_hash, &hashit)) {
Expand All @@ -292,7 +288,7 @@ static void _purge_orig(struct bat_priv *bat_priv)
frag_list_free(&orig_node->frag_list);
}

spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);

softif_neigh_purge(bat_priv);
}
Expand Down Expand Up @@ -324,7 +320,6 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
int batman_count = 0;
int last_seen_secs;
int last_seen_msecs;
unsigned long flags;

if ((!bat_priv->primary_if) ||
(bat_priv->primary_if->if_status != IF_ACTIVE)) {
Expand All @@ -346,7 +341,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
"Originator", "last-seen", "#", TQ_MAX_VALUE, "Nexthop",
"outgoingIF", "Potential nexthops");

spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);

while (hash_iterate(bat_priv->orig_hash, &hashit)) {
bucket = hlist_entry(hashit.walk, struct element_t, hlist);
Expand Down Expand Up @@ -377,7 +372,7 @@ int orig_seq_print_text(struct seq_file *seq, void *offset)
batman_count++;
}

spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);

if ((batman_count == 0))
seq_printf(seq, "No batman nodes in range ...\n");
Expand Down Expand Up @@ -419,13 +414,12 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
{
struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
struct orig_node *orig_node;
unsigned long flags;
HASHIT(hashit);
struct element_t *bucket;

/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);

while (hash_iterate(bat_priv->orig_hash, &hashit)) {
bucket = hlist_entry(hashit.walk, struct element_t, hlist);
Expand All @@ -435,11 +429,11 @@ int orig_hash_add_if(struct batman_if *batman_if, int max_if_num)
goto err;
}

spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
return 0;

err:
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
return -ENOMEM;
}

Expand Down Expand Up @@ -500,14 +494,13 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
struct bat_priv *bat_priv = netdev_priv(batman_if->soft_iface);
struct batman_if *batman_if_tmp;
struct orig_node *orig_node;
unsigned long flags;
HASHIT(hashit);
struct element_t *bucket;
int ret;

/* resize all orig nodes because orig_node->bcast_own(_sum) depend on
* if_num */
spin_lock_irqsave(&bat_priv->orig_hash_lock, flags);
spin_lock_bh(&bat_priv->orig_hash_lock);

while (hash_iterate(bat_priv->orig_hash, &hashit)) {
bucket = hlist_entry(hashit.walk, struct element_t, hlist);
Expand Down Expand Up @@ -538,10 +531,10 @@ int orig_hash_del_if(struct batman_if *batman_if, int max_if_num)
rcu_read_unlock();

batman_if->if_num = -1;
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
return 0;

err:
spin_unlock_irqrestore(&bat_priv->orig_hash_lock, flags);
spin_unlock_bh(&bat_priv->orig_hash_lock);
return -ENOMEM;
}
Loading

0 comments on commit 7a18deb

Please sign in to comment.