svn commit: r358096 - head/sys/sys

Jeff Roberson jeff at FreeBSD.org
Wed Feb 19 08:15:21 UTC 2020


Author: jeff
Date: Wed Feb 19 08:15:20 2020
New Revision: 358096
URL: https://svnweb.freebsd.org/changeset/base/358096

Log:
  Type validating smr protected pointer accessors.
  
  This API is intended to provide some measure of safety with SMR
  protected pointers.  A struct wrapper provides type checking and
  a guarantee that all access is mediated by the API unless abused.  All
  modifying functions take an assert as an argument to guarantee that
  the required synchronization is present.
  
  Reviewed by:	kib, markj, mjg
  Differential Revision:	https://reviews.freebsd.org/D23711

Modified:
  head/sys/sys/smr.h

Modified: head/sys/sys/smr.h
==============================================================================
--- head/sys/sys/smr.h	Wed Feb 19 06:28:55 2020	(r358095)
+++ head/sys/sys/smr.h	Wed Feb 19 08:15:20 2020	(r358096)
@@ -77,6 +77,98 @@ struct smr {
 #define	SMR_ASSERT_NOT_ENTERED(smr)					\
     KASSERT(!SMR_ENTERED(smr), ("In smr section."));
 
+#define SMR_ASSERT(ex, fn)						\
+    KASSERT((ex), (fn ": Assertion " #ex " failed at %s:%d", __FILE__, __LINE__))
+
+/*
+ * SMR Accessors are meant to provide safe access to SMR protected
+ * pointers and prevent misuse and accidental access.
+ *
+ * Accessors are grouped by type:
+ * entered	- Use while in a read section (between smr_enter/smr_exit())
+ * serialized 	- Use while holding a lock that serializes writers.   Updates
+ *		  are synchronized with readers via included barriers.
+ * unserialized	- Use after the memory is out of scope and not visible to
+ *		  readers.
+ *
+ * All acceses include a parameter for an assert to verify the required
+ * synchronization.  For example, a writer might use:
+ *
+ * smr_serilized_store(pointer, value, mtx_owned(&writelock));
+ *
+ * These are only enabled in INVARIANTS kernels.
+ */
+
+/* Type restricting pointer access to force smr accessors. */
+#define	SMR_TYPE_DECLARE(smrtype, type)					\
+typedef struct {							\
+	type	__ptr;		/* Do not access directly */		\
+} smrtype
+
+/*
+ * Read from an SMR protected pointer while in a read section.
+ */
+#define	smr_entered_load(p, smr) ({					\
+	SMR_ASSERT(SMR_ENTERED((smr)), "smr_entered_load");		\
+	(__typeof((p)->__ptr))atomic_load_acq_ptr((uintptr_t *)&(p)->__ptr); \
+})
+
+/*
+ * Read from an SMR protected pointer while serialized by an
+ * external mechanism.  'ex' should contain an assert that the
+ * external mechanism is held.  i.e. mtx_owned()
+ */
+#define	smr_serialized_load(p, ex) ({					\
+	SMR_ASSERT(ex, "smr_serialized_load");				\
+	(__typeof((p)->__ptr))atomic_load_ptr((uintptr_t *)&(p)->__ptr);\
+})
+
+/*
+ * Store 'v' to an SMR protected pointer while serialized by an
+ * external mechanism.  'ex' should contain an assert that the
+ * external mechanism is held.  i.e. mtx_owned()
+ */
+#define	smr_serialized_store(p, v, ex) do {				\
+	SMR_ASSERT(ex, "smr_serialized_store");				\
+	__typeof((p)->__ptr) _v = (v);					\
+	atomic_store_rel_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v);	\
+} while (0)
+
+/*
+ * swap 'v' with an SMR protected pointer and return the old value
+ * while serialized by an external mechanism.  'ex' should contain
+ * an assert that the external mechanism is provided.  i.e. mtx_owned()
+ */
+#define	smr_serialized_swap(p, v, ex) ({				\
+	SMR_ASSERT(ex, "smr_serialized_swap");				\
+	__typeof((p)->__ptr) _v = (v);					\
+	/* Release barrier guarantees contents are visible to reader */ \
+	atomic_thread_fence_rel();					\
+	(__typeof((p)->__ptr))atomic_swap_ptr(				\
+	    (uintptr_t *)&(p)->__ptr, (uintptr_t)_v);			\
+})
+
+/*
+ * Read from an SMR protected pointer when no serialization is required
+ * such as in the destructor callback or when the caller guarantees other
+ * synchronization.
+ */
+#define	smr_unserialized_load(p, ex) ({					\
+	SMR_ASSERT(ex, "smr_unserialized_load");			\
+	(__typeof((p)->__ptr))atomic_load_ptr((uintptr_t *)&(p)->__ptr);\
+})
+
+/*
+ * Store to an SMR protected pointer when no serialiation is required
+ * such as in the destructor callback or when the caller guarantees other
+ * synchronization.
+ */
+#define	smr_unserialized_store(p, v, ex) do {				\
+	SMR_ASSERT(ex, "smr_unserialized_store");			\
+	__typeof((p)->__ptr) _v = (v);					\
+	atomic_store_ptr((uintptr_t *)&(p)->__ptr, (uintptr_t)_v);	\
+} while (0)
+
 /*
  * Return the current write sequence number.
  */


More information about the svn-src-all mailing list