From patchwork Mon Jun 3 23:25:42 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Pedersen X-Patchwork-Id: 2656151 Return-Path: X-Original-To: patchwork-linux-wireless@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 340823FC23 for ; Mon, 3 Jun 2013 23:28:12 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1758784Ab3FCX2K (ORCPT ); Mon, 3 Jun 2013 19:28:10 -0400 Received: from mail-pb0-f47.google.com ([209.85.160.47]:49188 "EHLO mail-pb0-f47.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1757860Ab3FCX2I (ORCPT ); Mon, 3 Jun 2013 19:28:08 -0400 Received: by mail-pb0-f47.google.com with SMTP id rr4so6336868pbb.6 for ; Mon, 03 Jun 2013 16:28:07 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=from:to:cc:subject:date:message-id:x-mailer:x-gm-message-state; bh=/VUYgv21ZD6Q7oVafAB3TFpxHp4XDIgWzry3OZVmPGM=; b=Yina7yi9DsynNSPpQImct/X0G9pXr3iGqC8Nvbbg64UWmBNW6Vbp5RPMLfh4bTlNjx PZxgOf+scI8TqNUeR74fZTvu3R6cdcmuedjm7F+SD7diIr113tCzinq4aD1E1N0Ghjd8 KL2mW5fti4sozW5wD4qTlgd5kX0WC486ta5VSOFjchTyiH41W/rMOmrqtFcjrqFfuK1J 5PW+uI5g6qIpvG7T+FUTKxsWUruymYNOzLu+rsALIDSxdspGVIKLj610S+2nouxPdX43 JKc9l/uaPHbC/+0EKSr52DK63pgS/ac9iPn5I6sQomuWBkcfeQZi4aaYbu3ArDy7zmxa 02vQ== X-Received: by 10.68.196.196 with SMTP id io4mr25904909pbc.166.1370302087777; Mon, 03 Jun 2013 16:28:07 -0700 (PDT) Received: from cable.lan (70-35-43-50.static.wiline.com. [70.35.43.50]) by mx.google.com with ESMTPSA id kv2sm60658953pbc.28.2013.06.03.16.28.05 for (version=TLSv1.2 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Mon, 03 Jun 2013 16:28:06 -0700 (PDT) From: Thomas Pedersen To: Johannes Berg Cc: linux-wireless , open80211s , Thomas Pedersen Subject: [PATCH 1/2] mac80211: fix mesh deadlock Date: Mon, 3 Jun 2013 16:25:42 -0700 Message-Id: <1370301943-13867-1-git-send-email-thomas@cozybit.com> X-Mailer: git-send-email 1.7.10.4 X-Gm-Message-State: ALoCoQn7ULYmRW4bc/K/e0IRt6HblOwyl6iQuIKPld6/aezs4TOvjSw4VqkSZxj4QnEwwNttDmom Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org The patch "cfg80211/mac80211: use cfg80211 wdev mutex in mac80211" introduced several deadlocks by converting the ifmsh->mtx to wdev->mtx. Solve these by: 1. drop the cancel_work_sync() in ieee80211_stop_mesh(). Instead make the mesh work conditional on whether the mesh is running or not. 2. lock the mesh work with sdata_lock() to protect beacon updates and prevent races with wdev->mesh_id_len or cfg80211. Signed-off-by: Thomas Pedersen --- net/mac80211/mesh.c | 29 +++++++++++++++++------------ net/mac80211/mesh_plink.c | 7 +------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 73a597b..d5faf91 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -579,9 +579,7 @@ static void ieee80211_mesh_housekeeping(struct ieee80211_sub_if_data *sdata) mesh_path_expire(sdata); changed = mesh_accept_plinks_update(sdata); - sdata_lock(sdata); ieee80211_mbss_info_change_notify(sdata, changed); - sdata_unlock(sdata); mod_timer(&ifmsh->housekeeping_timer, round_jiffies(jiffies + @@ -788,12 +786,10 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) sdata->vif.bss_conf.enable_beacon = false; clear_bit(SDATA_STATE_OFFCHANNEL_BEACON_STOPPED, &sdata->state); ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED); - sdata_lock(sdata); bcn = rcu_dereference_protected(ifmsh->beacon, lockdep_is_held(&sdata->wdev.mtx)); rcu_assign_pointer(ifmsh->beacon, NULL); kfree_rcu(bcn, rcu_head); - sdata_unlock(sdata); /* flush STAs and mpaths on this iface */ sta_info_flush(sdata); @@ -806,14 +802,6 @@ void ieee80211_stop_mesh(struct ieee80211_sub_if_data *sdata) del_timer_sync(&sdata->u.mesh.housekeeping_timer); del_timer_sync(&sdata->u.mesh.mesh_path_root_timer); del_timer_sync(&sdata->u.mesh.mesh_path_timer); - /* - * If the timer fired while we waited for it, it will have - * requeued the work. Now the work will be running again - * but will not rearm the timer again because it checks - * whether the interface is running, which, at this point, - * it no longer is. - */ - cancel_work_sync(&sdata->work); local->fif_other_bss--; atomic_dec(&local->iff_allmultis); @@ -954,6 +942,12 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt; u16 stype; + sdata_lock(sdata); + + /* mesh already went down */ + if (!sdata->wdev.mesh_id_len) + goto out; + rx_status = IEEE80211_SKB_RXCB(skb); mgmt = (struct ieee80211_mgmt *) skb->data; stype = le16_to_cpu(mgmt->frame_control) & IEEE80211_FCTL_STYPE; @@ -971,12 +965,20 @@ void ieee80211_mesh_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata, ieee80211_mesh_rx_mgmt_action(sdata, mgmt, skb->len, rx_status); break; } +out: + sdata_unlock(sdata); } void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) { struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh; + sdata_lock(sdata); + + /* mesh already went down */ + if (!sdata->wdev.mesh_id_len) + goto out; + if (ifmsh->preq_queue_len && time_after(jiffies, ifmsh->last_preq + msecs_to_jiffies(ifmsh->mshcfg.dot11MeshHWMPpreqMinInterval))) @@ -996,6 +998,9 @@ void ieee80211_mesh_work(struct ieee80211_sub_if_data *sdata) if (test_and_clear_bit(MESH_WORK_DRIFT_ADJUST, &ifmsh->wrkq_flags)) mesh_sync_adjust_tbtt(sdata); + +out: + sdata_unlock(sdata); } void ieee80211_mesh_notify_scan_completed(struct ieee80211_local *local) diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index 6c4da99..09bebed 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -517,9 +517,7 @@ void mesh_neighbour_update(struct ieee80211_sub_if_data *sdata, ieee80211_mps_frame_release(sta, elems); out: rcu_read_unlock(); - sdata_lock(sdata); ieee80211_mbss_info_change_notify(sdata, changed); - sdata_unlock(sdata); } static void mesh_plink_timer(unsigned long data) @@ -1070,9 +1068,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, rcu_read_unlock(); - if (changed) { - sdata_lock(sdata); + if (changed) ieee80211_mbss_info_change_notify(sdata, changed); - sdata_unlock(sdata); - } }