| From foo@baz Thu Dec 21 09:02:40 CET 2017 |
| From: Ying Xue <ying.xue@windriver.com> |
| Date: Tue, 21 Mar 2017 10:47:49 +0100 |
| Subject: tipc: fix nametbl deadlock at tipc_nametbl_unsubscribe |
| |
| From: Ying Xue <ying.xue@windriver.com> |
| |
| |
| [ Upstream commit 557d054c01da0337ca81de9e9d9206d57245b57e ] |
| |
| Until now, tipc_nametbl_unsubscribe() is called at subscriptions |
| reference count cleanup. Usually the subscriptions cleanup is |
| called at subscription timeout or at subscription cancel or at |
| subscriber delete. |
| |
| We have ignored the possibility of this being called from other |
| locations, which causes deadlock as we try to grab the |
| tn->nametbl_lock while holding it already. |
| |
| CPU1: CPU2: |
| ---------- ---------------- |
| tipc_nametbl_publish |
| spin_lock_bh(&tn->nametbl_lock) |
| tipc_nametbl_insert_publ |
| tipc_nameseq_insert_publ |
| tipc_subscrp_report_overlap |
| tipc_subscrp_get |
| tipc_subscrp_send_event |
| tipc_close_conn |
| tipc_subscrb_release_cb |
| tipc_subscrb_delete |
| tipc_subscrp_put |
| tipc_subscrp_put |
| tipc_subscrp_kref_release |
| tipc_nametbl_unsubscribe |
| spin_lock_bh(&tn->nametbl_lock) |
| <<grab nametbl_lock again>> |
| |
| CPU1: CPU2: |
| ---------- ---------------- |
| tipc_nametbl_stop |
| spin_lock_bh(&tn->nametbl_lock) |
| tipc_purge_publications |
| tipc_nameseq_remove_publ |
| tipc_subscrp_report_overlap |
| tipc_subscrp_get |
| tipc_subscrp_send_event |
| tipc_close_conn |
| tipc_subscrb_release_cb |
| tipc_subscrb_delete |
| tipc_subscrp_put |
| tipc_subscrp_put |
| tipc_subscrp_kref_release |
| tipc_nametbl_unsubscribe |
| spin_lock_bh(&tn->nametbl_lock) |
| <<grab nametbl_lock again>> |
| |
| In this commit, we advance the calling of tipc_nametbl_unsubscribe() |
| from the refcount cleanup to the intended callers. |
| |
| Fixes: d094c4d5f5c7 ("tipc: add subscription refcount to avoid invalid delete") |
| Reported-by: John Thompson <thompa.atl@gmail.com> |
| Acked-by: Jon Maloy <jon.maloy@ericsson.com> |
| Signed-off-by: Ying Xue <ying.xue@windriver.com> |
| Signed-off-by: Parthasarathy Bhuvaragan <parthasarathy.bhuvaragan@ericsson.com> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/tipc/subscr.c | 7 ++++++- |
| 1 file changed, 6 insertions(+), 1 deletion(-) |
| |
| --- a/net/tipc/subscr.c |
| +++ b/net/tipc/subscr.c |
| @@ -141,6 +141,11 @@ void tipc_subscrp_report_overlap(struct |
| static void tipc_subscrp_timeout(unsigned long data) |
| { |
| struct tipc_subscription *sub = (struct tipc_subscription *)data; |
| + struct tipc_subscriber *subscriber = sub->subscriber; |
| + |
| + spin_lock_bh(&subscriber->lock); |
| + tipc_nametbl_unsubscribe(sub); |
| + spin_unlock_bh(&subscriber->lock); |
| |
| /* Notify subscriber of timeout */ |
| tipc_subscrp_send_event(sub, sub->evt.s.seq.lower, sub->evt.s.seq.upper, |
| @@ -173,7 +178,6 @@ static void tipc_subscrp_kref_release(st |
| struct tipc_subscriber *subscriber = sub->subscriber; |
| |
| spin_lock_bh(&subscriber->lock); |
| - tipc_nametbl_unsubscribe(sub); |
| list_del(&sub->subscrp_list); |
| atomic_dec(&tn->subscription_count); |
| spin_unlock_bh(&subscriber->lock); |
| @@ -205,6 +209,7 @@ static void tipc_subscrb_subscrp_delete( |
| if (s && memcmp(s, &sub->evt.s, sizeof(struct tipc_subscr))) |
| continue; |
| |
| + tipc_nametbl_unsubscribe(sub); |
| tipc_subscrp_get(sub); |
| spin_unlock_bh(&subscriber->lock); |
| tipc_subscrp_delete(sub); |