From patchwork Thu Oct 18 08:43:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sebastian Andrzej Siewior X-Patchwork-Id: 985735 X-Patchwork-Delegate: davem@davemloft.net Return-Path: X-Original-To: patchwork-incoming-netdev@ozlabs.org Delivered-To: patchwork-incoming-netdev@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netdev-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=linutronix.de Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 42bMyL2wmzz9sBn for ; Thu, 18 Oct 2018 19:43:22 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727649AbeJRQnP (ORCPT ); Thu, 18 Oct 2018 12:43:15 -0400 Received: from Galois.linutronix.de ([146.0.238.70]:33622 "EHLO Galois.linutronix.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727455AbeJRQnP (ORCPT ); Thu, 18 Oct 2018 12:43:15 -0400 Received: from bigeasy by Galois.linutronix.de with local (Exim 4.80) (envelope-from ) id 1gD3ti-0001Mc-KG; Thu, 18 Oct 2018 10:43:14 +0200 Date: Thu, 18 Oct 2018 10:43:13 +0200 From: Sebastian Andrzej Siewior To: Stephen Hemminger Cc: netdev@vger.kernel.org, virtualization@lists.linux-foundation.org, tglx@linutronix.de, Toshiaki Makita , "Michael S. Tsirkin" , Jason Wang , "David S. Miller" Subject: [PATCH] virtio_net: add local_bh_disable() around u64_stats_update_begin Message-ID: <20181018084313.oopu34iwfwgkcwwc@linutronix.de> References: <20181016165545.guksrl23ulcudxrk@linutronix.de> <20181016110114.73e2b248@xeon-e3> <20181016184206.coukhtgmlr32hyl7@linutronix.de> <20181016114414.23ea73c3@xeon-e3> MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: <20181016114414.23ea73c3@xeon-e3> User-Agent: NeoMutt/20180716 Sender: netdev-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netdev@vger.kernel.org on 32bit, lockdep notices that virtnet_open() and refill_work() invoke try_fill_recv() from process context while virtnet_receive() invokes the same function from BH context. The problem that the seqcounter within u64_stats_update_begin() may deadlock if it is interrupted by BH and then acquired again. Introduce u64_stats_update_begin_bh() which disables BH on 32bit architectures. Since the BH might interrupt the worker, this new function should not limited to SMP like the others which are expected to be used in softirq. With this change we might lose increments but this is okay. The important part that the two 32bit parts of the 64bit counter are not corrupted. Fixes: 461f03dc99cf6 ("virtio_net: Add kick stats"). Suggested-by: Stephen Hemminger Signed-off-by: Sebastian Andrzej Siewior --- drivers/net/virtio_net.c | 4 ++-- include/linux/u64_stats_sync.h | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index dab504ec5e502..fbcfb4d272336 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -1206,9 +1206,9 @@ static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq, break; } while (rq->vq->num_free); if (virtqueue_kick_prepare(rq->vq) && virtqueue_notify(rq->vq)) { - u64_stats_update_begin(&rq->stats.syncp); + u64_stats_update_begin_bh(&rq->stats.syncp); rq->stats.kicks++; - u64_stats_update_end(&rq->stats.syncp); + u64_stats_update_end_bh(&rq->stats.syncp); } return !oom; diff --git a/include/linux/u64_stats_sync.h b/include/linux/u64_stats_sync.h index a27604f99ed04..46b6ad6175628 100644 --- a/include/linux/u64_stats_sync.h +++ b/include/linux/u64_stats_sync.h @@ -90,6 +90,22 @@ static inline void u64_stats_update_end(struct u64_stats_sync *syncp) #endif } +static inline void u64_stats_update_begin_bh(struct u64_stats_sync *syncp) +{ +#if BITS_PER_LONG==32 + local_bh_disable(); + write_seqcount_begin(&syncp->seq); +#endif +} + +static inline void u64_stats_update_end_bh(struct u64_stats_sync *syncp) +{ +#if BITS_PER_LONG==32 + write_seqcount_end(&syncp->seq); + local_bh_enable(); +#endif +} + static inline unsigned long u64_stats_update_begin_irqsave(struct u64_stats_sync *syncp) {