Commit fb9962f3 authored by Ying Xue's avatar Ying Xue Committed by David S. Miller

tipc: ensure all name sequences are properly protected with its lock

TIPC internally created a name table which is used to store name
sequences. Now there is a read-write lock - tipc_nametbl_lock to
protect the table, and each name sequence saved in the table is
protected with its private lock. When a name sequence is inserted
or removed to or from the table, its members might need to change.
Therefore, in normal case, the two locks must be held while TIPC
operates the table. However, there are still several places where
we only hold tipc_nametbl_lock without proprerly obtaining name
sequence lock, which might cause the corruption of name sequence.
Signed-off-by: default avatarYing Xue <ying.xue@windriver.com>
Reviewed-by: default avatarErik Hugne <erik.hugne@ericsson.com>
Reviewed-by: default avatarJon Maloy <jon.maloy@ericsson.com>
Tested-by: default avatarErik Hugne <erik.hugne@ericsson.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 38622f41
...@@ -172,18 +172,6 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea ...@@ -172,18 +172,6 @@ static struct name_seq *tipc_nameseq_create(u32 type, struct hlist_head *seq_hea
return nseq; return nseq;
} }
/*
* nameseq_delete_empty - deletes a name sequence structure if now unused
*/
static void nameseq_delete_empty(struct name_seq *seq)
{
if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init(&seq->ns_list);
kfree(seq->sseqs);
kfree(seq);
}
}
/** /**
* nameseq_find_subseq - find sub-sequence (if any) matching a name instance * nameseq_find_subseq - find sub-sequence (if any) matching a name instance
* *
...@@ -476,6 +464,7 @@ static struct name_seq *nametbl_find_seq(u32 type) ...@@ -476,6 +464,7 @@ static struct name_seq *nametbl_find_seq(u32 type)
struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
u32 scope, u32 node, u32 port, u32 key) u32 scope, u32 node, u32 port, u32 key)
{ {
struct publication *publ;
struct name_seq *seq = nametbl_find_seq(type); struct name_seq *seq = nametbl_find_seq(type);
int index = hash(type); int index = hash(type);
...@@ -492,8 +481,11 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper, ...@@ -492,8 +481,11 @@ struct publication *tipc_nametbl_insert_publ(u32 type, u32 lower, u32 upper,
if (!seq) if (!seq)
return NULL; return NULL;
return tipc_nameseq_insert_publ(seq, type, lower, upper, spin_lock_bh(&seq->lock);
publ = tipc_nameseq_insert_publ(seq, type, lower, upper,
scope, node, port, key); scope, node, port, key);
spin_unlock_bh(&seq->lock);
return publ;
} }
struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
...@@ -505,8 +497,16 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower, ...@@ -505,8 +497,16 @@ struct publication *tipc_nametbl_remove_publ(u32 type, u32 lower,
if (!seq) if (!seq)
return NULL; return NULL;
spin_lock_bh(&seq->lock);
publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key); publ = tipc_nameseq_remove_publ(seq, lower, node, ref, key);
nameseq_delete_empty(seq); if (!seq->first_free && list_empty(&seq->subscriptions)) {
hlist_del_init(&seq->ns_list);
spin_unlock_bh(&seq->lock);
kfree(seq->sseqs);
kfree(seq);
return publ;
}
spin_unlock_bh(&seq->lock);
return publ; return publ;
} }
...@@ -539,10 +539,10 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode) ...@@ -539,10 +539,10 @@ u32 tipc_nametbl_translate(u32 type, u32 instance, u32 *destnode)
seq = nametbl_find_seq(type); seq = nametbl_find_seq(type);
if (unlikely(!seq)) if (unlikely(!seq))
goto not_found; goto not_found;
spin_lock_bh(&seq->lock);
sseq = nameseq_find_subseq(seq, instance); sseq = nameseq_find_subseq(seq, instance);
if (unlikely(!sseq)) if (unlikely(!sseq))
goto not_found; goto no_match;
spin_lock_bh(&seq->lock);
info = sseq->info; info = sseq->info;
/* Closest-First Algorithm */ /* Closest-First Algorithm */
...@@ -624,7 +624,6 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, ...@@ -624,7 +624,6 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
goto exit; goto exit;
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
sseq = seq->sseqs + nameseq_locate_subseq(seq, lower); sseq = seq->sseqs + nameseq_locate_subseq(seq, lower);
sseq_stop = seq->sseqs + seq->first_free; sseq_stop = seq->sseqs + seq->first_free;
for (; sseq != sseq_stop; sseq++) { for (; sseq != sseq_stop; sseq++) {
...@@ -642,7 +641,6 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit, ...@@ -642,7 +641,6 @@ int tipc_nametbl_mc_translate(u32 type, u32 lower, u32 upper, u32 limit,
if (info->cluster_list_size != info->node_list_size) if (info->cluster_list_size != info->node_list_size)
res = 1; res = 1;
} }
spin_unlock_bh(&seq->lock); spin_unlock_bh(&seq->lock);
exit: exit:
read_unlock_bh(&tipc_nametbl_lock); read_unlock_bh(&tipc_nametbl_lock);
...@@ -747,8 +745,14 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s) ...@@ -747,8 +745,14 @@ void tipc_nametbl_unsubscribe(struct tipc_subscription *s)
if (seq != NULL) { if (seq != NULL) {
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
list_del_init(&s->nameseq_list); list_del_init(&s->nameseq_list);
spin_unlock_bh(&seq->lock); if (!seq->first_free && list_empty(&seq->subscriptions)) {
nameseq_delete_empty(seq); hlist_del_init(&seq->ns_list);
spin_unlock_bh(&seq->lock);
kfree(seq->sseqs);
kfree(seq);
} else {
spin_unlock_bh(&seq->lock);
}
} }
write_unlock_bh(&tipc_nametbl_lock); write_unlock_bh(&tipc_nametbl_lock);
} }
...@@ -964,6 +968,7 @@ static void tipc_purge_publications(struct name_seq *seq) ...@@ -964,6 +968,7 @@ static void tipc_purge_publications(struct name_seq *seq)
struct sub_seq *sseq; struct sub_seq *sseq;
struct name_info *info; struct name_info *info;
spin_lock_bh(&seq->lock);
sseq = seq->sseqs; sseq = seq->sseqs;
info = sseq->info; info = sseq->info;
list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) { list_for_each_entry_safe(publ, safe, &info->zone_list, zone_list) {
...@@ -972,6 +977,8 @@ static void tipc_purge_publications(struct name_seq *seq) ...@@ -972,6 +977,8 @@ static void tipc_purge_publications(struct name_seq *seq)
kfree(publ); kfree(publ);
} }
hlist_del_init(&seq->ns_list); hlist_del_init(&seq->ns_list);
spin_lock_bh(&seq->lock);
kfree(seq->sseqs); kfree(seq->sseqs);
kfree(seq); kfree(seq);
} }
...@@ -1127,7 +1134,6 @@ static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type, ...@@ -1127,7 +1134,6 @@ static int __tipc_nl_seq_list(struct tipc_nl_msg *msg, u32 *last_type,
hlist_for_each_entry_from(seq, ns_list) { hlist_for_each_entry_from(seq, ns_list) {
spin_lock_bh(&seq->lock); spin_lock_bh(&seq->lock);
err = __tipc_nl_subseq_list(msg, seq, last_lower, err = __tipc_nl_subseq_list(msg, seq, last_lower,
last_publ); last_publ);
......
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