linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/2] seqlock: simplify SEQCOUNT_LOCKNAME()
@ 2023-10-12 14:31 Oleg Nesterov
  2023-10-12 14:32 ` [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer Oleg Nesterov
  2023-10-12 18:35 ` [tip: locking/core] locking/seqlock: Simplify SEQCOUNT_LOCKNAME() tip-bot2 for Oleg Nesterov
  0 siblings, 2 replies; 8+ messages in thread
From: Oleg Nesterov @ 2023-10-12 14:31 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Alexey Gladkov, Ingo Molnar, Will Deacon, Waiman Long,
	Boqun Feng, linux-kernel

1. Kill the "lockmember" argument. It is always s->lock plus
   __seqprop_##lockname##_sequence() already uses s->lock and
   ignores "lockmember".

2. Kill the "lock_acquire" argument. __seqprop_##lockname##_sequence()
   can use the same "lockbase" prefix for _lock and _unlock.

Apart from line numbers, gcc -E outputs the same code.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/seqlock.h | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index e9bd2f65d7f4..b9a30c62ffe4 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -191,11 +191,9 @@ static inline void seqcount_lockdep_reader_access(const seqcount_t *s)
  * @lockname:		"LOCKNAME" part of seqcount_LOCKNAME_t
  * @locktype:		LOCKNAME canonical C data type
  * @preemptible:	preemptibility of above locktype
- * @lockmember:		argument for lockdep_assert_held()
- * @lockbase:		associated lock release function (prefix only)
- * @lock_acquire:	associated lock acquisition function (full call)
+ * @lockbase:		prefix for associated lock/unlock
  */
-#define SEQCOUNT_LOCKNAME(lockname, locktype, preemptible, lockmember, lockbase, lock_acquire) \
+#define SEQCOUNT_LOCKNAME(lockname, locktype, preemptible, lockbase)	\
 typedef struct seqcount_##lockname {					\
 	seqcount_t		seqcount;				\
 	__SEQ_LOCK(locktype	*lock);					\
@@ -216,7 +214,7 @@ __seqprop_##lockname##_sequence(const seqcount_##lockname##_t *s)	\
 		return seq;						\
 									\
 	if (preemptible && unlikely(seq & 1)) {				\
-		__SEQ_LOCK(lock_acquire);				\
+		__SEQ_LOCK(lockbase##_lock(s->lock));			\
 		__SEQ_LOCK(lockbase##_unlock(s->lock));			\
 									\
 		/*							\
@@ -242,7 +240,7 @@ __seqprop_##lockname##_preemptible(const seqcount_##lockname##_t *s)	\
 static __always_inline void						\
 __seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)		\
 {									\
-	__SEQ_LOCK(lockdep_assert_held(lockmember));			\
+	__SEQ_LOCK(lockdep_assert_held(s->lock));			\
 }
 
 /*
@@ -271,10 +269,10 @@ static inline void __seqprop_assert(const seqcount_t *s)
 
 #define __SEQ_RT	IS_ENABLED(CONFIG_PREEMPT_RT)
 
-SEQCOUNT_LOCKNAME(raw_spinlock, raw_spinlock_t,  false,    s->lock,        raw_spin, raw_spin_lock(s->lock))
-SEQCOUNT_LOCKNAME(spinlock,     spinlock_t,      __SEQ_RT, s->lock,        spin,     spin_lock(s->lock))
-SEQCOUNT_LOCKNAME(rwlock,       rwlock_t,        __SEQ_RT, s->lock,        read,     read_lock(s->lock))
-SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     s->lock,        mutex,    mutex_lock(s->lock))
+SEQCOUNT_LOCKNAME(raw_spinlock, raw_spinlock_t,  false,    raw_spin)
+SEQCOUNT_LOCKNAME(spinlock,     spinlock_t,      __SEQ_RT, spin)
+SEQCOUNT_LOCKNAME(rwlock,       rwlock_t,        __SEQ_RT, read)
+SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
 
 /*
  * SEQCNT_LOCKNAME_ZERO - static initializer for seqcount_LOCKNAME_t
-- 
2.25.1.362.g51ebf55



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer
  2023-10-12 14:31 [PATCH v2 1/2] seqlock: simplify SEQCOUNT_LOCKNAME() Oleg Nesterov
@ 2023-10-12 14:32 ` Oleg Nesterov
  2023-10-12 18:21   ` Ingo Molnar
  2023-10-12 18:35   ` [tip: locking/core] locking/seqlock: Change __seqprop() to return the function pointer tip-bot2 for Oleg Nesterov
  2023-10-12 18:35 ` [tip: locking/core] locking/seqlock: Simplify SEQCOUNT_LOCKNAME() tip-bot2 for Oleg Nesterov
  1 sibling, 2 replies; 8+ messages in thread
From: Oleg Nesterov @ 2023-10-12 14:32 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Alexey Gladkov, Ingo Molnar, Will Deacon, Waiman Long,
	Boqun Feng, linux-kernel

This simplifies the macro and makes it easy to add the new seqprop's
with 2 or more args.

Plus this way we do not lose the type info, the (void*) type cast is
no longer needed.

And the latter reveals the problem: a lot of seqcount_t helpers pass
the "const seqcount_t *s" argument to __seqprop_ptr(seqcount_t *s)
but (before this patch) "(void *)(s)" masked the problem.

So this patch changes __seqprop_ptr() and __seqprop_##lockname##_ptr()
to accept the "const LOCKNAME *s" argument. This is not nice either,
they need to drop the constness on return because these helpers are used
by both the readers and writers, but at least it is clear what's going on.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
---
 include/linux/seqlock.h | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index b9a30c62ffe4..bf1435ffe24f 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -200,9 +200,9 @@ typedef struct seqcount_##lockname {					\
 } seqcount_##lockname##_t;						\
 									\
 static __always_inline seqcount_t *					\
-__seqprop_##lockname##_ptr(seqcount_##lockname##_t *s)			\
+__seqprop_##lockname##_ptr(const seqcount_##lockname##_t *s)		\
 {									\
-	return &s->seqcount;						\
+	return (void *)&s->seqcount; /* drop const */			\
 }									\
 									\
 static __always_inline unsigned						\
@@ -247,9 +247,9 @@ __seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)		\
  * __seqprop() for seqcount_t
  */
 
-static inline seqcount_t *__seqprop_ptr(seqcount_t *s)
+static inline seqcount_t *__seqprop_ptr(const seqcount_t *s)
 {
-	return s;
+	return (void *)s; /* drop const */
 }
 
 static inline unsigned __seqprop_sequence(const seqcount_t *s)
@@ -292,19 +292,19 @@ SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
 #define SEQCNT_WW_MUTEX_ZERO(name, lock) 	SEQCOUNT_LOCKNAME_ZERO(name, lock)
 
 #define __seqprop_case(s, lockname, prop)				\
-	seqcount_##lockname##_t: __seqprop_##lockname##_##prop((void *)(s))
+	seqcount_##lockname##_t: __seqprop_##lockname##_##prop
 
 #define __seqprop(s, prop) _Generic(*(s),				\
-	seqcount_t:		__seqprop_##prop((void *)(s)),		\
+	seqcount_t:		__seqprop_##prop,			\
 	__seqprop_case((s),	raw_spinlock,	prop),			\
 	__seqprop_case((s),	spinlock,	prop),			\
 	__seqprop_case((s),	rwlock,		prop),			\
 	__seqprop_case((s),	mutex,		prop))
 
-#define seqprop_ptr(s)			__seqprop(s, ptr)
-#define seqprop_sequence(s)		__seqprop(s, sequence)
-#define seqprop_preemptible(s)		__seqprop(s, preemptible)
-#define seqprop_assert(s)		__seqprop(s, assert)
+#define seqprop_ptr(s)			__seqprop(s, ptr)(s)
+#define seqprop_sequence(s)		__seqprop(s, sequence)(s)
+#define seqprop_preemptible(s)		__seqprop(s, preemptible)(s)
+#define seqprop_assert(s)		__seqprop(s, assert)(s)
 
 /**
  * __read_seqcount_begin() - begin a seqcount_t read section w/o barrier
-- 
2.25.1.362.g51ebf55



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer
  2023-10-12 14:32 ` [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer Oleg Nesterov
@ 2023-10-12 18:21   ` Ingo Molnar
  2023-10-12 19:24     ` Linus Torvalds
  2023-10-12 18:35   ` [tip: locking/core] locking/seqlock: Change __seqprop() to return the function pointer tip-bot2 for Oleg Nesterov
  1 sibling, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2023-10-12 18:21 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Peter Zijlstra, Alexey Gladkov, Ingo Molnar, Will Deacon,
	Waiman Long, Boqun Feng, linux-kernel, Linus Torvalds,
	Thomas Gleixner


* Oleg Nesterov <oleg@redhat.com> wrote:

> This simplifies the macro and makes it easy to add the new seqprop's
> with 2 or more args.
> 
> Plus this way we do not lose the type info, the (void*) type cast is
> no longer needed.
> 
> And the latter reveals the problem: a lot of seqcount_t helpers pass
> the "const seqcount_t *s" argument to __seqprop_ptr(seqcount_t *s)
> but (before this patch) "(void *)(s)" masked the problem.
> 
> So this patch changes __seqprop_ptr() and __seqprop_##lockname##_ptr()
> to accept the "const LOCKNAME *s" argument. This is not nice either,
> they need to drop the constness on return because these helpers are used
> by both the readers and writers, but at least it is clear what's going on.

> +__seqprop_##lockname##_ptr(const seqcount_##lockname##_t *s)		\
>  {									\
> +	return (void *)&s->seqcount; /* drop const */			\
>  }									\

> +static inline seqcount_t *__seqprop_ptr(const seqcount_t *s)
>  {
> +	return (void *)s; /* drop const */
>  }

Okay, so dropping 'const' makes sense in terms of staying bug-compatible
with the  previous API and not build-breaking the world - but could we
perhaps follow this up with fixups of the type misuse and then a removal
of the forced type casts from these APIs?

Meanwhile I'm applying your patches to tip:locking/core, unless someone objects.

Thanks,

	Ingo

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [tip: locking/core] locking/seqlock: Change __seqprop() to return the function pointer
  2023-10-12 14:32 ` [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer Oleg Nesterov
  2023-10-12 18:21   ` Ingo Molnar
@ 2023-10-12 18:35   ` tip-bot2 for Oleg Nesterov
  1 sibling, 0 replies; 8+ messages in thread
From: tip-bot2 for Oleg Nesterov @ 2023-10-12 18:35 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Oleg Nesterov, Ingo Molnar, Peter Zijlstra, Waiman Long,
	Will Deacon, Thomas Gleixner, Linus Torvalds, Paul E. McKenney,
	x86, linux-kernel

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     e6115c6f7a0ce3388cc60b69a284facf78b5dbfd
Gitweb:        https://git.kernel.org/tip/e6115c6f7a0ce3388cc60b69a284facf78b5dbfd
Author:        Oleg Nesterov <oleg@redhat.com>
AuthorDate:    Thu, 12 Oct 2023 16:32:27 +02:00
Committer:     Ingo Molnar <mingo@kernel.org>
CommitterDate: Thu, 12 Oct 2023 20:18:21 +02:00

locking/seqlock: Change __seqprop() to return the function pointer

This simplifies the macro and makes it easy to add the new seqprop's
with 2 or more args.

Plus this way we do not lose the type info, the (void*) type cast is
no longer needed.

And the latter reveals the problem: a lot of seqcount_t helpers pass
the "const seqcount_t *s" argument to __seqprop_ptr(seqcount_t *s)
but (before this patch) "(void *)(s)" masked the problem.

So this patch changes __seqprop_ptr() and __seqprop_##lockname##_ptr()
to accept the "const LOCKNAME *s" argument. This is not nice either,
they need to drop the constness on return because these helpers are used
by both the readers and writers, but at least it is clear what's going on.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20231012143227.GA16143@redhat.com
---
 include/linux/seqlock.h | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 7e7109d..4b8dcd3 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -200,9 +200,9 @@ typedef struct seqcount_##lockname {					\
 } seqcount_##lockname##_t;						\
 									\
 static __always_inline seqcount_t *					\
-__seqprop_##lockname##_ptr(seqcount_##lockname##_t *s)			\
+__seqprop_##lockname##_ptr(const seqcount_##lockname##_t *s)		\
 {									\
-	return &s->seqcount;						\
+	return (void *)&s->seqcount; /* drop const */			\
 }									\
 									\
 static __always_inline unsigned						\
@@ -247,9 +247,9 @@ __seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)		\
  * __seqprop() for seqcount_t
  */
 
-static inline seqcount_t *__seqprop_ptr(seqcount_t *s)
+static inline seqcount_t *__seqprop_ptr(const seqcount_t *s)
 {
-	return s;
+	return (void *)s; /* drop const */
 }
 
 static inline unsigned __seqprop_sequence(const seqcount_t *s)
@@ -292,19 +292,19 @@ SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
 #define SEQCNT_WW_MUTEX_ZERO(name, lock) 	SEQCOUNT_LOCKNAME_ZERO(name, lock)
 
 #define __seqprop_case(s, lockname, prop)				\
-	seqcount_##lockname##_t: __seqprop_##lockname##_##prop((void *)(s))
+	seqcount_##lockname##_t: __seqprop_##lockname##_##prop
 
 #define __seqprop(s, prop) _Generic(*(s),				\
-	seqcount_t:		__seqprop_##prop((void *)(s)),		\
+	seqcount_t:		__seqprop_##prop,			\
 	__seqprop_case((s),	raw_spinlock,	prop),			\
 	__seqprop_case((s),	spinlock,	prop),			\
 	__seqprop_case((s),	rwlock,		prop),			\
 	__seqprop_case((s),	mutex,		prop))
 
-#define seqprop_ptr(s)			__seqprop(s, ptr)
-#define seqprop_sequence(s)		__seqprop(s, sequence)
-#define seqprop_preemptible(s)		__seqprop(s, preemptible)
-#define seqprop_assert(s)		__seqprop(s, assert)
+#define seqprop_ptr(s)			__seqprop(s, ptr)(s)
+#define seqprop_sequence(s)		__seqprop(s, sequence)(s)
+#define seqprop_preemptible(s)		__seqprop(s, preemptible)(s)
+#define seqprop_assert(s)		__seqprop(s, assert)(s)
 
 /**
  * __read_seqcount_begin() - begin a seqcount_t read section w/o barrier

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [tip: locking/core] locking/seqlock: Simplify SEQCOUNT_LOCKNAME()
  2023-10-12 14:31 [PATCH v2 1/2] seqlock: simplify SEQCOUNT_LOCKNAME() Oleg Nesterov
  2023-10-12 14:32 ` [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer Oleg Nesterov
@ 2023-10-12 18:35 ` tip-bot2 for Oleg Nesterov
  1 sibling, 0 replies; 8+ messages in thread
From: tip-bot2 for Oleg Nesterov @ 2023-10-12 18:35 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: Oleg Nesterov, Ingo Molnar, Peter Zijlstra, Waiman Long,
	Will Deacon, Thomas Gleixner, Linus Torvalds, Paul E. McKenney,
	x86, linux-kernel

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     f995443f01b4dbcce723539b99050ce69b319e58
Gitweb:        https://git.kernel.org/tip/f995443f01b4dbcce723539b99050ce69b319e58
Author:        Oleg Nesterov <oleg@redhat.com>
AuthorDate:    Thu, 12 Oct 2023 16:31:58 +02:00
Committer:     Ingo Molnar <mingo@kernel.org>
CommitterDate: Thu, 12 Oct 2023 20:18:20 +02:00

locking/seqlock: Simplify SEQCOUNT_LOCKNAME()

1. Kill the "lockmember" argument. It is always s->lock plus
   __seqprop_##lockname##_sequence() already uses s->lock and
   ignores "lockmember".

2. Kill the "lock_acquire" argument. __seqprop_##lockname##_sequence()
   can use the same "lockbase" prefix for _lock and _unlock.

Apart from line numbers, gcc -E outputs the same code.

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Paul E. McKenney <paulmck@kernel.org>
Link: https://lore.kernel.org/r/20231012143158.GA16133@redhat.com
---
 include/linux/seqlock.h | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index af518e4..7e7109d 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -191,11 +191,9 @@ static inline void seqcount_lockdep_reader_access(const seqcount_t *s)
  * @lockname:		"LOCKNAME" part of seqcount_LOCKNAME_t
  * @locktype:		LOCKNAME canonical C data type
  * @preemptible:	preemptibility of above locktype
- * @lockmember:		argument for lockdep_assert_held()
- * @lockbase:		associated lock release function (prefix only)
- * @lock_acquire:	associated lock acquisition function (full call)
+ * @lockbase:		prefix for associated lock/unlock
  */
-#define SEQCOUNT_LOCKNAME(lockname, locktype, preemptible, lockmember, lockbase, lock_acquire) \
+#define SEQCOUNT_LOCKNAME(lockname, locktype, preemptible, lockbase)	\
 typedef struct seqcount_##lockname {					\
 	seqcount_t		seqcount;				\
 	__SEQ_LOCK(locktype	*lock);					\
@@ -216,7 +214,7 @@ __seqprop_##lockname##_sequence(const seqcount_##lockname##_t *s)	\
 		return seq;						\
 									\
 	if (preemptible && unlikely(seq & 1)) {				\
-		__SEQ_LOCK(lock_acquire);				\
+		__SEQ_LOCK(lockbase##_lock(s->lock));			\
 		__SEQ_LOCK(lockbase##_unlock(s->lock));			\
 									\
 		/*							\
@@ -242,7 +240,7 @@ __seqprop_##lockname##_preemptible(const seqcount_##lockname##_t *s)	\
 static __always_inline void						\
 __seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)		\
 {									\
-	__SEQ_LOCK(lockdep_assert_held(lockmember));			\
+	__SEQ_LOCK(lockdep_assert_held(s->lock));			\
 }
 
 /*
@@ -271,10 +269,10 @@ static inline void __seqprop_assert(const seqcount_t *s)
 
 #define __SEQ_RT	IS_ENABLED(CONFIG_PREEMPT_RT)
 
-SEQCOUNT_LOCKNAME(raw_spinlock, raw_spinlock_t,  false,    s->lock,        raw_spin, raw_spin_lock(s->lock))
-SEQCOUNT_LOCKNAME(spinlock,     spinlock_t,      __SEQ_RT, s->lock,        spin,     spin_lock(s->lock))
-SEQCOUNT_LOCKNAME(rwlock,       rwlock_t,        __SEQ_RT, s->lock,        read,     read_lock(s->lock))
-SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     s->lock,        mutex,    mutex_lock(s->lock))
+SEQCOUNT_LOCKNAME(raw_spinlock, raw_spinlock_t,  false,    raw_spin)
+SEQCOUNT_LOCKNAME(spinlock,     spinlock_t,      __SEQ_RT, spin)
+SEQCOUNT_LOCKNAME(rwlock,       rwlock_t,        __SEQ_RT, read)
+SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
 
 /*
  * SEQCNT_LOCKNAME_ZERO - static initializer for seqcount_LOCKNAME_t

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer
  2023-10-12 18:21   ` Ingo Molnar
@ 2023-10-12 19:24     ` Linus Torvalds
  2023-10-13  8:46       ` [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts Ingo Molnar
  0 siblings, 1 reply; 8+ messages in thread
From: Linus Torvalds @ 2023-10-12 19:24 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Oleg Nesterov, Peter Zijlstra, Alexey Gladkov, Ingo Molnar,
	Will Deacon, Waiman Long, Boqun Feng, linux-kernel,
	Thomas Gleixner

On Thu, 12 Oct 2023 at 11:21, Ingo Molnar <mingo@kernel.org> wrote:
>
> Okay, so dropping 'const' makes sense in terms of staying bug-compatible
> with the  previous API and not build-breaking the world - but could we
> perhaps follow this up with fixups of the type misuse and then a removal
> of the forced type casts from these APIs?

No. The use of 'const' here is *not* a bug.

The thing is, 'const' doesn't mean what you seem to think it means. A
'const' pointer in C in no way means that the target is constant - it
means that *THIS* use of the pointer will not write to the target!

Those may sound similar, but they are very very very different.

In particular, for the sequence

        seq = raw_seqcount_begin(seq_ptr);
        ...
        if (read_seqcount_retry(seq_ptr, seq))
                goto retry;

then 'seq_ptr' really *is* a 'const' pointer. The reader very much
does not write to it, and this very much is part of the fundamental
design.

The above is *literally* what sequence locking is all about: readers
are pure readers.

So no, making it a 'const seqptr_t' is absolutely not a bug. It's very
much a FUNDAMENTAL FEATURE of sequence locks.

Now, I'm not sure how much we actually take advantage of this and
there may not be very many cases of this all, but I really think this
is fundamental to the whole data structure, and there are most
definitely cases where we probably *should* take more advantage of the
fact that a read_seqcount is a read-only op.

For example, I think a function like 'dget_parent()' should actually
take a 'const struct dentry *dentry' as its argument, and the seqcount
is embedded inside that dentry and as such would also be const.

Right now the dentry code doesn't actually do that, because this isn't
one of the areas we have constified, but it's conceptually the right
thing to do. We use the dentry argument in a read-only manner
(although the *parent* that we look up then is written to, and in the
case of a root dentry, the parent may end up being the same as the
original).

Note that the 'const' should only be an issue for the begin/retry
cases, and obviously not for the write ones, but those readers do use
the seqprop_ptr() helper. So those absolutely need to handle the const
case.

So no, the cast wasn't "masking" anything at all. The 'const' is real.

            Linus

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts
  2023-10-12 19:24     ` Linus Torvalds
@ 2023-10-13  8:46       ` Ingo Molnar
  2023-10-13 16:10         ` Oleg Nesterov
  0 siblings, 1 reply; 8+ messages in thread
From: Ingo Molnar @ 2023-10-13  8:46 UTC (permalink / raw)
  To: Linus Torvalds
  Cc: Oleg Nesterov, Peter Zijlstra, Alexey Gladkov, Ingo Molnar,
	Will Deacon, Waiman Long, Boqun Feng, linux-kernel,
	Thomas Gleixner


* Linus Torvalds <torvalds@linux-foundation.org> wrote:

> On Thu, 12 Oct 2023 at 11:21, Ingo Molnar <mingo@kernel.org> wrote:
> >
> > Okay, so dropping 'const' makes sense in terms of staying bug-compatible
> > with the  previous API and not build-breaking the world - but could we
> > perhaps follow this up with fixups of the type misuse and then a removal
> > of the forced type casts from these APIs?
> 
> No. The use of 'const' here is *not* a bug.
> 
> The thing is, 'const' doesn't mean what you seem to think it means. A
> 'const' pointer in C in no way means that the target is constant - it
> means that *THIS* use of the pointer will not write to the target!

Yeah, that is absolutely what I too think 'const' means - and sorry, I 
didn't expand: I meant something like the patch below, which clearly 
separates the 'const' from the non-const pointer uses within 
<linux/seqlock.h> and removes the two forced type casts I was unhappy 
about.

The 'bug' was that the __seqprop_*ptr() wrapper was used with both const 
and non-const pointers, and we forced a type and lost a tiny bit of 
potential const propagation. The code was fine and I should not have called 
it a 'bug', but I consider the dropping of 'const' a bad pattern, and I 
sometimes exaggerate problems to trick^W convince developers to continue 
working along a given path...

In hindsight my "break the world" expectation was overblown too: our const 
propagation through these methods was almost complete already, and the 
fixes stayed within <linux/seqlock.h>.

This patch could probably be split into two patches. Lightly tested only.

Does this work for you?

Thanks,

	Ingo

===================>
From: Ingo Molnar <mingo@kernel.org>
Date: Fri, 13 Oct 2023 10:15:46 +0200
Subject: [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts

Currently __seqprop_ptr() is an inline function that must chose to either
use 'const' or non-const seqcount related pointers - but this results in
the undesirable loss of 'const' propagation, via a forced type cast.

The easiest solution would be to turn the pointer wrappers into macros that 
pass through whatever type is passed to them - but the clever maze of 
seqlock API instantiation macros relies on the GCC CPP '##' macro 
extension, which isn't recursive, so inline functions must be used here.

So create two wrapper variants instead: 'ptr' and 'const_ptr', and pick the
right one for the codepaths that are const: read_seqcount_begin() and
read_seqcount_retry().

This cleans up type handling and allows the removal of all type forcing.

No change in functionality.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Waiman Long <longman@redhat.com>
Cc: Will Deacon <will.deacon@arm.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Paul E. McKenney <paulmck@kernel.org>
---
 include/linux/seqlock.h | 26 +++++++++++++++++++-------
 1 file changed, 19 insertions(+), 7 deletions(-)

diff --git a/include/linux/seqlock.h b/include/linux/seqlock.h
index 4b8dcd3a0d93..80f21d2ca2aa 100644
--- a/include/linux/seqlock.h
+++ b/include/linux/seqlock.h
@@ -200,9 +200,15 @@ typedef struct seqcount_##lockname {					\
 } seqcount_##lockname##_t;						\
 									\
 static __always_inline seqcount_t *					\
-__seqprop_##lockname##_ptr(const seqcount_##lockname##_t *s)		\
+__seqprop_##lockname##_ptr(seqcount_##lockname##_t *s)			\
 {									\
-	return (void *)&s->seqcount; /* drop const */			\
+	return &s->seqcount;						\
+}									\
+									\
+static __always_inline const seqcount_t *				\
+__seqprop_##lockname##_const_ptr(const seqcount_##lockname##_t *s)	\
+{									\
+	return &s->seqcount;						\
 }									\
 									\
 static __always_inline unsigned						\
@@ -247,9 +253,14 @@ __seqprop_##lockname##_assert(const seqcount_##lockname##_t *s)		\
  * __seqprop() for seqcount_t
  */
 
-static inline seqcount_t *__seqprop_ptr(const seqcount_t *s)
+static inline seqcount_t *__seqprop_ptr(seqcount_t *s)
 {
-	return (void *)s; /* drop const */
+	return s;
+}
+
+static inline const seqcount_t *__seqprop_const_ptr(const seqcount_t *s)
+{
+	return s;
 }
 
 static inline unsigned __seqprop_sequence(const seqcount_t *s)
@@ -302,6 +313,7 @@ SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
 	__seqprop_case((s),	mutex,		prop))
 
 #define seqprop_ptr(s)			__seqprop(s, ptr)(s)
+#define seqprop_const_ptr(s)		__seqprop(s, const_ptr)(s)
 #define seqprop_sequence(s)		__seqprop(s, sequence)(s)
 #define seqprop_preemptible(s)		__seqprop(s, preemptible)(s)
 #define seqprop_assert(s)		__seqprop(s, assert)(s)
@@ -353,7 +365,7 @@ SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
  */
 #define read_seqcount_begin(s)						\
 ({									\
-	seqcount_lockdep_reader_access(seqprop_ptr(s));			\
+	seqcount_lockdep_reader_access(seqprop_const_ptr(s));		\
 	raw_read_seqcount_begin(s);					\
 })
 
@@ -419,7 +431,7 @@ SEQCOUNT_LOCKNAME(mutex,        struct mutex,    true,     mutex)
  * Return: true if a read section retry is required, else false
  */
 #define __read_seqcount_retry(s, start)					\
-	do___read_seqcount_retry(seqprop_ptr(s), start)
+	do___read_seqcount_retry(seqprop_const_ptr(s), start)
 
 static inline int do___read_seqcount_retry(const seqcount_t *s, unsigned start)
 {
@@ -439,7 +451,7 @@ static inline int do___read_seqcount_retry(const seqcount_t *s, unsigned start)
  * Return: true if a read section retry is required, else false
  */
 #define read_seqcount_retry(s, start)					\
-	do_read_seqcount_retry(seqprop_ptr(s), start)
+	do_read_seqcount_retry(seqprop_const_ptr(s), start)
 
 static inline int do_read_seqcount_retry(const seqcount_t *s, unsigned start)
 {

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts
  2023-10-13  8:46       ` [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts Ingo Molnar
@ 2023-10-13 16:10         ` Oleg Nesterov
  0 siblings, 0 replies; 8+ messages in thread
From: Oleg Nesterov @ 2023-10-13 16:10 UTC (permalink / raw)
  To: Ingo Molnar
  Cc: Linus Torvalds, Peter Zijlstra, Alexey Gladkov, Ingo Molnar,
	Will Deacon, Waiman Long, Boqun Feng, linux-kernel,
	Thomas Gleixner

On 10/13, Ingo Molnar wrote:
>
> So create two wrapper variants instead: 'ptr' and 'const_ptr', and pick the
> right one for the codepaths that are const: read_seqcount_begin() and
> read_seqcount_retry().
>
> This cleans up type handling and allows the removal of all type forcing.

Too late, but nevertheless

Reviewed-by: Oleg Nesterov <oleg@redhat.com>


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2023-10-13 16:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-10-12 14:31 [PATCH v2 1/2] seqlock: simplify SEQCOUNT_LOCKNAME() Oleg Nesterov
2023-10-12 14:32 ` [PATCH v2 2/2] seqlock: change __seqprop() to return the function pointer Oleg Nesterov
2023-10-12 18:21   ` Ingo Molnar
2023-10-12 19:24     ` Linus Torvalds
2023-10-13  8:46       ` [PATCH] locking/seqlock: Propagate 'const' pointers within read-only methods, remove forced type casts Ingo Molnar
2023-10-13 16:10         ` Oleg Nesterov
2023-10-12 18:35   ` [tip: locking/core] locking/seqlock: Change __seqprop() to return the function pointer tip-bot2 for Oleg Nesterov
2023-10-12 18:35 ` [tip: locking/core] locking/seqlock: Simplify SEQCOUNT_LOCKNAME() tip-bot2 for Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).