From owner-svn-src-head@freebsd.org  Thu Feb  6 20:51:46 2020
Return-Path: <owner-svn-src-head@freebsd.org>
Delivered-To: svn-src-head@mailman.nyi.freebsd.org
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1])
 by mailman.nyi.freebsd.org (Postfix) with ESMTP id C6CC523AA35;
 Thu,  6 Feb 2020 20:51:46 +0000 (UTC)
 (envelope-from jeff@FreeBSD.org)
Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org
 [IPv6:2610:1c1:1:606c::19:3])
 (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
 server-signature RSA-PSS (4096 bits)
 client-signature RSA-PSS (4096 bits) client-digest SHA256)
 (Client CN "mxrelay.nyi.freebsd.org",
 Issuer "Let's Encrypt Authority X3" (verified OK))
 by mx1.freebsd.org (Postfix) with ESMTPS id 48D9b64tGXz3C4V;
 Thu,  6 Feb 2020 20:51:46 +0000 (UTC)
 (envelope-from jeff@FreeBSD.org)
Received: from repo.freebsd.org (repo.freebsd.org
 [IPv6:2610:1c1:1:6068::e6a:0])
 (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
 (Client did not present a certificate)
 by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A2B53218A0;
 Thu,  6 Feb 2020 20:51:46 +0000 (UTC)
 (envelope-from jeff@FreeBSD.org)
Received: from repo.freebsd.org ([127.0.1.37])
 by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id 016KpksH000138;
 Thu, 6 Feb 2020 20:51:46 GMT (envelope-from jeff@FreeBSD.org)
Received: (from jeff@localhost)
 by repo.freebsd.org (8.15.2/8.15.2/Submit) id 016KpkjY000137;
 Thu, 6 Feb 2020 20:51:46 GMT (envelope-from jeff@FreeBSD.org)
Message-Id: <202002062051.016KpkjY000137@repo.freebsd.org>
X-Authentication-Warning: repo.freebsd.org: jeff set sender to
 jeff@FreeBSD.org using -f
From: Jeff Roberson <jeff@FreeBSD.org>
Date: Thu, 6 Feb 2020 20:51:46 +0000 (UTC)
To: src-committers@freebsd.org, svn-src-all@freebsd.org,
 svn-src-head@freebsd.org
Subject: svn commit: r357641 - head/sys/kern
X-SVN-Group: head
X-SVN-Commit-Author: jeff
X-SVN-Commit-Paths: head/sys/kern
X-SVN-Commit-Revision: 357641
X-SVN-Commit-Repository: base
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
X-BeenThere: svn-src-head@freebsd.org
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: SVN commit messages for the src tree for head/-current
 <svn-src-head.freebsd.org>
List-Unsubscribe: <https://lists.freebsd.org/mailman/options/svn-src-head>,
 <mailto:svn-src-head-request@freebsd.org?subject=unsubscribe>
List-Archive: <http://lists.freebsd.org/pipermail/svn-src-head/>
List-Post: <mailto:svn-src-head@freebsd.org>
List-Help: <mailto:svn-src-head-request@freebsd.org?subject=help>
List-Subscribe: <https://lists.freebsd.org/mailman/listinfo/svn-src-head>,
 <mailto:svn-src-head-request@freebsd.org?subject=subscribe>
X-List-Received-Date: Thu, 06 Feb 2020 20:51:46 -0000

Author: jeff
Date: Thu Feb  6 20:51:46 2020
New Revision: 357641
URL: https://svnweb.freebsd.org/changeset/base/357641

Log:
  Fix a race in smr_advance() that could result in unnecessary poll calls.
  
  This was relatively harmless but surprising to see in counters.  The
  race occurred when rd_seq was read after the goal was updated and we
  incorrectly calculated the delta between them.
  
  Reviewed by:	rlibby
  Differential Revision:	https://reviews.freebsd.org/D23464

Modified:
  head/sys/kern/subr_smr.c

Modified: head/sys/kern/subr_smr.c
==============================================================================
--- head/sys/kern/subr_smr.c	Thu Feb  6 20:47:50 2020	(r357640)
+++ head/sys/kern/subr_smr.c	Thu Feb  6 20:51:46 2020	(r357641)
@@ -160,7 +160,7 @@ static uma_zone_t smr_zone;
 #define	SMR_SEQ_INCR	(UINT_MAX / 10000)
 #define	SMR_SEQ_INIT	(UINT_MAX - 100000)
 /* Force extra polls to test the integer overflow detection. */
-#define	SMR_SEQ_MAX_DELTA	(1000)
+#define	SMR_SEQ_MAX_DELTA	(SMR_SEQ_INCR * 32)
 #define	SMR_SEQ_MAX_ADVANCE	SMR_SEQ_MAX_DELTA / 2
 #endif
 
@@ -188,7 +188,7 @@ smr_seq_t
 smr_advance(smr_t smr)
 {
 	smr_shared_t s;
-	smr_seq_t goal;
+	smr_seq_t goal, s_rd_seq;
 
 	/*
 	 * It is illegal to enter while in an smr section.
@@ -203,12 +203,18 @@ smr_advance(smr_t smr)
 	atomic_thread_fence_rel();
 
 	/*
+	 * Load the current read seq before incrementing the goal so
+	 * we are guaranteed it is always < goal.
+	 */
+	s = zpcpu_get(smr)->c_shared;
+	s_rd_seq = atomic_load_acq_int(&s->s_rd_seq);
+
+	/*
 	 * Increment the shared write sequence by 2.  Since it is
 	 * initialized to 1 this means the only valid values are
 	 * odd and an observed value of 0 in a particular CPU means
 	 * it is not currently in a read section.
 	 */
-	s = zpcpu_get(smr)->c_shared;
 	goal = atomic_fetchadd_int(&s->s_wr_seq, SMR_SEQ_INCR) + SMR_SEQ_INCR;
 	counter_u64_add(advance, 1);
 
@@ -217,7 +223,7 @@ smr_advance(smr_t smr)
 	 * far ahead of the read sequence number.  This keeps the
 	 * wrap detecting arithmetic working in pathological cases.
 	 */
-	if (goal - atomic_load_int(&s->s_rd_seq) >= SMR_SEQ_MAX_DELTA) {
+	if (SMR_SEQ_DELTA(goal, s_rd_seq) >= SMR_SEQ_MAX_DELTA) {
 		counter_u64_add(advance_wait, 1);
 		smr_wait(smr, goal - SMR_SEQ_MAX_ADVANCE);
 	}