tipc: Prevent null pointer error when removing a node subscription
authorAllan Stephens <Allan.Stephens@windriver.com>
Wed, 23 Feb 2011 18:51:15 +0000 (13:51 -0500)
committerPaul Gortmaker <paul.gortmaker@windriver.com>
Sun, 13 Mar 2011 20:35:16 +0000 (16:35 -0400)
Prevents a null pointer dereference from occurring if a node subscription
is triggered at the same time that the subscribing port or publication is
terminating the subscription. The problem arises if the triggering routine
asynchronously activates and deregisters the node subscription while
deregistration is already underway -- the deregistration routine may find
that the pointer it has just verified to be non-NULL is now NULL.
To avoid this race condition the triggering routine now simply marks the
node subscription as defunct (to prevent it from re-activating)
instead of deregistering it. The subscription is now both deregistered
and destroyed only when the subscribing port or publication code terminates
the node subscription.

Signed-off-by: Allan Stephens <Allan.Stephens@windriver.com>
Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com>
net/tipc/name_distr.c
net/tipc/node.c

index 483c226c9581a10a598866a1b57e815be79113ab..1d4a18aa9cccd8fe68f3f081008ce972952492f4 100644 (file)
@@ -2,7 +2,7 @@
  * net/tipc/name_distr.c: TIPC name distribution code
  *
  * Copyright (c) 2000-2006, Ericsson AB
- * Copyright (c) 2005, Wind River Systems
+ * Copyright (c) 2005, 2010-2011, Wind River Systems
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -221,7 +221,6 @@ exit:
  * In rare cases the link may have come back up again when this
  * function is called, and we have two items representing the same
  * publication. Nudge this item's key to distinguish it from the other.
- * (Note: Publication's node subscription is already unsubscribed.)
  */
 
 static void node_is_down(struct publication *publ)
@@ -232,6 +231,8 @@ static void node_is_down(struct publication *publ)
        publ->key += 1222345;
        p = tipc_nametbl_remove_publ(publ->type, publ->lower,
                                     publ->node, publ->ref, publ->key);
+       if (p)
+               tipc_nodesub_unsubscribe(&p->subscr);
        write_unlock_bh(&tipc_nametbl_lock);
 
        if (p != publ) {
index 14f98c81d313b3370dead7fa51d034985ed207de..8926caaf1fc5922d26afa369c6da13f1c6e483b4 100644 (file)
@@ -327,7 +327,7 @@ static void node_cleanup_finished(unsigned long node_addr)
 
 static void node_lost_contact(struct tipc_node *n_ptr)
 {
-       struct tipc_node_subscr *ns, *tns;
+       struct tipc_node_subscr *ns;
        char addr_string[16];
        u32 i;
 
@@ -365,11 +365,12 @@ static void node_lost_contact(struct tipc_node *n_ptr)
        }
 
        /* Notify subscribers */
-       list_for_each_entry_safe(ns, tns, &n_ptr->nsub, nodesub_list) {
-               ns->node = NULL;
-               list_del_init(&ns->nodesub_list);
-               tipc_k_signal((Handler)ns->handle_node_down,
-                             (unsigned long)ns->usr_handle);
+       list_for_each_entry(ns, &n_ptr->nsub, nodesub_list) {
+               if (ns->handle_node_down) {
+                       tipc_k_signal((Handler)ns->handle_node_down,
+                                     (unsigned long)ns->usr_handle);
+                       ns->handle_node_down = NULL;
+               }
        }
 
        /* Prevent re-contact with node until all cleanup is done */