From patchwork Thu Feb 3 17:03:55 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marek Lindner X-Patchwork-Id: 797 Return-Path: Received: from nm3.bullet.mail.ukl.yahoo.com (nm3.bullet.mail.ukl.yahoo.com [217.146.182.224]) by open-mesh.org (Postfix) with SMTP id 17690154272 for ; Thu, 3 Feb 2011 18:07:55 +0100 (CET) Received: from [217.146.183.216] by nm3.bullet.mail.ukl.yahoo.com with NNFMP; 03 Feb 2011 17:07:54 -0000 Received: from [217.146.183.168] by tm9.bullet.mail.ukl.yahoo.com with NNFMP; 03 Feb 2011 17:07:54 -0000 Received: from [127.0.0.1] by omp1009.mail.ukl.yahoo.com with NNFMP; 03 Feb 2011 17:07:54 -0000 X-Yahoo-Newman-Id: 538755.18125.bm@omp1009.mail.ukl.yahoo.com Received: (qmail 24091 invoked from network); 3 Feb 2011 17:07:54 -0000 DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=s1024; d=yahoo.de; h=DKIM-Signature:Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=r4G+eF9HwkxSELhawbI/MjM8FufzcBhrE8QpopYkM5TsAeoq2hxfRJfKe6Ivbq47FDaROo04BwFealPkGXmgTr+7lJ1+aPViLhDs8kohlcQD9aqWn8WKNHrKV78lUitMIbJrzd4uPQbGSsofX/LZTErKaJlBu8oz/mjH+clUgpM= ; DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yahoo.de; s=s1024; t=1296752874; bh=rU+PSls/jlxG2tGwq8df09bbBUYeg47/2dlD1aNyE7w=; h=Received:X-Yahoo-SMTP:X-YMail-OSG:X-Yahoo-Newman-Property:From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References; b=DuQP/ujC5hLnxzYH7f3+xB9baUdGInDSxBlbK2zABwO4jIxZDIYEugE4aLC6sHtDEKlOGLVE0iBotvqeyGYn/VVFdLvzRrr6sAuIsIxOas4OBdQXcrBWoRR3UYQDtdz+vI+wTkdkVr4r37Xl3yg34wTJsBrUqPFWivSw4t0mXiI= Received: from localhost (lindner_marek@81.57.254.118 with plain) by smtp125.mail.ukl.yahoo.com with SMTP; 03 Feb 2011 17:07:50 +0000 GMT X-Yahoo-SMTP: tW.h3tiswBBMXO2coYcbPigGD5Lt6zY_.Zc- X-YMail-OSG: hbh0kEQVM1nVpZPP4nTlW_c_3amYm8RXivwcfoa4996RK3m X.amXbpivId14L6vZ2ie9.7JF75kX13kKi_ZJM4eY1jthwPNmiWO7WKfmIPR XY.BrBeAczEKiQxVAU_KWeUluqEyqCXBbGhB9Dj94CvN3zKNqddMe72RYkxf vC4Tx1clS6UkISHLLJG4vrxrI7ZU.vRAokheP3es.bkCZ6pUtNvXSTGjt_WV TIL8ix7Pb6lKh6IHDSxvWfBvuoWY.bpHOVCQqj6FH2GMb9hG9aR6zSMXYwRh ChgYoJFUYAZfJElE- X-Yahoo-Newman-Property: ymail-3 From: Marek Lindner To: b.a.t.m.a.n@lists.open-mesh.org Date: Thu, 3 Feb 2011 18:03:55 +0100 Message-Id: <1296752637-4646-2-git-send-email-lindner_marek@yahoo.de> X-Mailer: git-send-email 1.7.2.3 In-Reply-To: <201102031802.52134.lindner_marek@yahoo.de> References: <201102031802.52134.lindner_marek@yahoo.de> Cc: Marek Lindner Subject: [B.A.T.M.A.N.] [PATCH 2/4] batman-adv: Correct rcu refcounting for softif_neigh X-BeenThere: b.a.t.m.a.n@lists.open-mesh.org X-Mailman-Version: 2.1.11 Precedence: list Reply-To: The list for a Better Approach To Mobile Ad-hoc Networking List-Id: The list for a Better Approach To Mobile Ad-hoc Networking List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Feb 2011 17:07:55 -0000 From: Sven Eckelmann It might be possible that 2 threads access the same data in the same rcu grace period. The first thread calls call_rcu() to decrement the refcount and free the data while the second thread increases the refcount to use the data. To avoid this race condition all refcount operations have to be atomic. Reported-by: Sven Eckelmann Signed-off-by: Marek Lindner --- batman-adv/soft-interface.c | 31 +++++++++++++++---------------- batman-adv/types.h | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/batman-adv/soft-interface.c b/batman-adv/soft-interface.c index 145e0f7..83dcccd 100644 --- a/batman-adv/soft-interface.c +++ b/batman-adv/soft-interface.c @@ -79,20 +79,18 @@ int my_skb_head_push(struct sk_buff *skb, unsigned int len) return 0; } -static void softif_neigh_free_ref(struct kref *refcount) +static void softif_neigh_free_rcu(struct rcu_head *rcu) { struct softif_neigh *softif_neigh; - softif_neigh = container_of(refcount, struct softif_neigh, refcount); + softif_neigh = container_of(rcu, struct softif_neigh, rcu); kfree(softif_neigh); } -static void softif_neigh_free_rcu(struct rcu_head *rcu) +static void softif_neigh_free_ref(struct softif_neigh *softif_neigh) { - struct softif_neigh *softif_neigh; - - softif_neigh = container_of(rcu, struct softif_neigh, rcu); - kref_put(&softif_neigh->refcount, softif_neigh_free_ref); + if (atomic_dec_and_test(&softif_neigh->refcount)) + call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); } void softif_neigh_purge(struct bat_priv *bat_priv) @@ -119,11 +117,10 @@ void softif_neigh_purge(struct bat_priv *bat_priv) softif_neigh->addr, softif_neigh->vid); softif_neigh_tmp = bat_priv->softif_neigh; bat_priv->softif_neigh = NULL; - kref_put(&softif_neigh_tmp->refcount, - softif_neigh_free_ref); + softif_neigh_free_ref(softif_neigh_tmp); } - call_rcu(&softif_neigh->rcu, softif_neigh_free_rcu); + softif_neigh_free_ref(softif_neigh); } spin_unlock_bh(&bat_priv->softif_neigh_lock); @@ -144,8 +141,11 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, if (softif_neigh->vid != vid) continue; + if (!atomic_inc_not_zero(&softif_neigh->refcount)) + continue; + softif_neigh->last_seen = jiffies; - goto found; + goto out; } softif_neigh = kzalloc(sizeof(struct softif_neigh), GFP_ATOMIC); @@ -155,15 +155,14 @@ static struct softif_neigh *softif_neigh_get(struct bat_priv *bat_priv, memcpy(softif_neigh->addr, addr, ETH_ALEN); softif_neigh->vid = vid; softif_neigh->last_seen = jiffies; - kref_init(&softif_neigh->refcount); + /* initialize with 2 - caller decrements counter by one */ + atomic_set(&softif_neigh->refcount, 2); INIT_HLIST_NODE(&softif_neigh->list); spin_lock_bh(&bat_priv->softif_neigh_lock); hlist_add_head_rcu(&softif_neigh->list, &bat_priv->softif_neigh_list); spin_unlock_bh(&bat_priv->softif_neigh_lock); -found: - kref_get(&softif_neigh->refcount); out: rcu_read_unlock(); return softif_neigh; @@ -267,7 +266,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, softif_neigh->addr, softif_neigh->vid); softif_neigh_tmp = bat_priv->softif_neigh; bat_priv->softif_neigh = softif_neigh; - kref_put(&softif_neigh_tmp->refcount, softif_neigh_free_ref); + softif_neigh_free_ref(softif_neigh_tmp); /* we need to hold the additional reference */ goto err; } @@ -285,7 +284,7 @@ static void softif_batman_recv(struct sk_buff *skb, struct net_device *dev, } out: - kref_put(&softif_neigh->refcount, softif_neigh_free_ref); + softif_neigh_free_ref(softif_neigh); err: kfree_skb(skb); return; diff --git a/batman-adv/types.h b/batman-adv/types.h index ca5f20a..8df6d9d 100644 --- a/batman-adv/types.h +++ b/batman-adv/types.h @@ -270,7 +270,7 @@ struct softif_neigh { uint8_t addr[ETH_ALEN]; unsigned long last_seen; short vid; - struct kref refcount; + atomic_t refcount; struct rcu_head rcu; };