git: 18e411233722 - main - linuxkpi: Add `seqcount_mutex_t` support in <linux/seqlock.h>

From: Emmanuel Vadot <manu_at_FreeBSD.org>
Date: Thu, 01 Dec 2022 14:04:40 UTC
The branch main has been updated by manu:

URL: https://cgit.FreeBSD.org/src/commit/?id=18e411233722088400624f21b66eb6687ebe8861

commit 18e411233722088400624f21b66eb6687ebe8861
Author:     Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
AuthorDate: 2022-12-01 13:58:27 +0000
Commit:     Emmanuel Vadot <manu@FreeBSD.org>
CommitDate: 2022-12-01 13:58:27 +0000

    linuxkpi: Add `seqcount_mutex_t` support in <linux/seqlock.h>
    
    To achieve that, the header uses the C11 type generic selection keyboard
    _Generic() because the macros are supposed to work with seqcount_t
    and seqcount_mutex_t.
    
    Differential Revision:  https://reviews.freebsd.org/D36965
---
 sys/compat/linuxkpi/common/include/linux/seqlock.h | 91 +++++++++++++++++++---
 1 file changed, 81 insertions(+), 10 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/seqlock.h b/sys/compat/linuxkpi/common/include/linux/seqlock.h
index 6e81e7a0fa45..4a5385f5e095 100644
--- a/sys/compat/linuxkpi/common/include/linux/seqlock.h
+++ b/sys/compat/linuxkpi/common/include/linux/seqlock.h
@@ -33,8 +33,11 @@
 #include <sys/systm.h>
 #include <sys/lock.h>
 #include <sys/mutex.h>
+#include <sys/rwlock.h>
 #include <sys/seqc.h>
 
+#include <linux/mutex.h>
+
 struct lock_class_key;
 
 struct seqcount {
@@ -48,6 +51,12 @@ struct seqlock {
 };
 typedef struct seqlock seqlock_t;
 
+struct seqcount_mutex {
+	struct mutex	*seqm_lock;
+	struct seqcount	 seqm_count;
+};
+typedef struct seqcount_mutex seqcount_mutex_t;
+
 static inline void
 __seqcount_init(struct seqcount *seqcount, const char *name __unused,
     struct lock_class_key *key __unused)
@@ -57,37 +66,99 @@ __seqcount_init(struct seqcount *seqcount, const char *name __unused,
 #define	seqcount_init(seqcount)	__seqcount_init(seqcount, NULL, NULL)
 
 static inline void
-write_seqcount_begin(struct seqcount *seqcount)
+seqcount_mutex_init(struct seqcount_mutex *seqcount, struct mutex *mutex)
+{
+	seqcount->seqm_lock = mutex;
+	seqcount_init(&seqcount->seqm_count);
+}
+
+#define	write_seqcount_begin(s)						\
+    _Generic(*(s),							\
+	struct seqcount:	lkpi_write_seqcount_begin,		\
+	struct seqcount_mutex:	lkpi_write_seqcount_mutex_begin		\
+    )(s)
+
+static inline void
+lkpi_write_seqcount_begin(struct seqcount *seqcount)
 {
 	seqc_sleepable_write_begin(&seqcount->seqc);
 }
 
 static inline void
-write_seqcount_end(struct seqcount *seqcount)
+lkpi_write_seqcount_mutex_begin(struct seqcount_mutex *seqcount)
+{
+	mutex_lock(seqcount->seqm_lock);
+	lkpi_write_seqcount_begin(&seqcount->seqm_count);
+}
+
+#define	write_seqcount_end(s)						\
+    _Generic(*(s),							\
+	struct seqcount:	lkpi_write_seqcount_end,		\
+	struct seqcount_mutex:	lkpi_write_seqcount_mutex_end		\
+    )(s)
+
+static inline void
+lkpi_write_seqcount_end(struct seqcount *seqcount)
 {
 	seqc_sleepable_write_end(&seqcount->seqc);
 }
 
-/*
- * XXX: Are predicts from inline functions still not honored by clang?
- */
-#define	__read_seqcount_retry(seqcount, gen)	\
-	(!seqc_consistent_no_fence(&(seqcount)->seqc, gen))
-#define	read_seqcount_retry(seqcount, gen)	\
-	(!seqc_consistent(&(seqcount)->seqc, gen))
+static inline void
+lkpi_write_seqcount_mutex_end(struct seqcount_mutex *seqcount)
+{
+	lkpi_write_seqcount_end(&seqcount->seqm_count);
+	mutex_unlock(seqcount->seqm_lock);
+}
+
+#define	read_seqcount_begin(s)						\
+    _Generic(*(s),							\
+	struct seqcount:	lkpi_read_seqcount_begin,		\
+	struct seqcount_mutex:	lkpi_read_seqcount_mutex_begin		\
+    )(s)
 
 static inline unsigned
-read_seqcount_begin(const struct seqcount *seqcount)
+lkpi_read_seqcount_begin(const struct seqcount *seqcount)
 {
 	return (seqc_read(&seqcount->seqc));
 }
 
+static inline unsigned
+lkpi_read_seqcount_mutex_begin(const struct seqcount_mutex *seqcount)
+{
+	return (lkpi_read_seqcount_begin(&seqcount->seqm_count));
+}
+
 static inline unsigned
 raw_read_seqcount(const struct seqcount *seqcount)
 {
 	return (seqc_read_any(&seqcount->seqc));
 }
 
+/*
+ * XXX: Are predicts from inline functions still not honored by clang?
+ */
+#define	__read_seqcount_retry(seqcount, gen)	\
+	(!seqc_consistent_no_fence(&(seqcount)->seqc, gen))
+#define	read_seqcount_retry(s, old)					\
+    _Generic(*(s),							\
+	struct seqcount:	lkpi_read_seqcount_retry,		\
+	struct seqcount_mutex:	lkpi_read_seqcount_mutex_retry		\
+    )(s, old)
+
+static inline int
+lkpi_read_seqcount_retry(
+    const struct seqcount *seqcount, unsigned int old)
+{
+	return (!seqc_consistent(&seqcount->seqc, old));
+}
+
+static inline int
+lkpi_read_seqcount_mutex_retry(
+    const struct seqcount_mutex *seqcount, unsigned int old)
+{
+	return (!seqc_consistent(&seqcount->seqm_count.seqc, old));
+}
+
 static inline void
 seqlock_init(struct seqlock *seqlock)
 {