Re: [PATCH] seqlock: Use WRITE_ONCE() when updating sequence

"Paul E. McKenney" <[email protected]>
Newsgroups org.kernel.vger.linux-toolchains,org.kernel.vger.linux-kernel
Message-ID <1d026056-5fa3-47e0-94cc-5212128ae00a@paulmck-laptop>
On Wed, Dec 18, 2024 at 06:12:41PM +0100, Peter Zijlstra wrote:
> 
> +linux-toolchains
> 
> On Wed, Dec 18, 2024 at 08:59:47AM -0800, Paul E. McKenney wrote:
> 
> > > Perhaps something like: (*(volatile unsigned int *)&s->sequence)++; ?
> > > I'd have to check what the compiler makes of that.
> > > 
> > > /me mucks about with godbolt for a bit...
> > > 
> > > GCC doesn't optimize that, but Clang does.
> > > 
> > > I would still very much refrain from making this change until both
> > > compilers can generate sane code for it.
> > 
> > Is GCC on track to do this, or do we need to encourage them?
> 
> I have no clue; probably wise to offer encouragement.

Hopefully your +linux-toolchain is a start.

> > Just to make sure I understand, your proposal is to create an INC_ONCE()
> > or similar, and add it once compiler support is there?  Seems reasonable
> > to me, just checking.
> 
> I suppose we can work in parallel, add INC_ONCE() now, but not have a
> proper definition for GCC.

This passes an rcutorture smoke test, so feel free to add:

Reviewed-by: Paul E. McKenney <[email protected]>

> ---
>  arch/riscv/kvm/vmid.c                     | 2 +-
>  arch/s390/kernel/idle.c                   | 2 +-
>  drivers/md/dm-vdo/indexer/index-session.c | 2 +-
>  fs/xfs/libxfs/xfs_iext_tree.c             | 2 +-
>  include/linux/compiler-gcc.h              | 5 +++++
>  include/linux/compiler.h                  | 4 ++++
>  include/linux/rcupdate_trace.h            | 2 +-
>  include/linux/srcutiny.h                  | 2 +-
>  io_uring/io_uring.c                       | 2 +-
>  kernel/rcu/srcutree.c                     | 4 ++--
>  kernel/rcu/tree_plugin.h                  | 2 +-
>  kernel/sched/fair.c                       | 2 +-
>  mm/kfence/kfence_test.c                   | 2 +-
>  security/apparmor/apparmorfs.c            | 2 +-
>  14 files changed, 22 insertions(+), 13 deletions(-)
> 
> diff --git a/arch/riscv/kvm/vmid.c b/arch/riscv/kvm/vmid.c
> index ddc98714ce8e..805a5acf669c 100644
> --- a/arch/riscv/kvm/vmid.c
> +++ b/arch/riscv/kvm/vmid.c
> @@ -90,7 +90,7 @@ void kvm_riscv_gstage_vmid_update(struct kvm_vcpu *vcpu)
>  
>  	/* First user of a new VMID version? */
>  	if (unlikely(vmid_next == 0)) {
> -		WRITE_ONCE(vmid_version, READ_ONCE(vmid_version) + 1);
> +		INC_ONCE(vmid_version);
>  		vmid_next = 1;
>  
>  		/*
> diff --git a/arch/s390/kernel/idle.c b/arch/s390/kernel/idle.c
> index 39cb8d0ae348..8fb7cd75fe62 100644
> --- a/arch/s390/kernel/idle.c
> +++ b/arch/s390/kernel/idle.c
> @@ -45,7 +45,7 @@ void account_idle_time_irq(void)
>  
>  	/* Account time spent with enabled wait psw loaded as idle time. */
>  	WRITE_ONCE(idle->idle_time, READ_ONCE(idle->idle_time) + idle_time);
> -	WRITE_ONCE(idle->idle_count, READ_ONCE(idle->idle_count) + 1);
> +	INC_ONC(idle->idle_count);
>  	account_idle_time(cputime_to_nsecs(idle_time));
>  }
>  
> diff --git a/drivers/md/dm-vdo/indexer/index-session.c b/drivers/md/dm-vdo/indexer/index-session.c
> index aee0914d604a..c5a7dee9dc66 100644
> --- a/drivers/md/dm-vdo/indexer/index-session.c
> +++ b/drivers/md/dm-vdo/indexer/index-session.c
> @@ -152,7 +152,7 @@ static void enter_callback_stage(struct uds_request *request)
>  
>  static inline void count_once(u64 *count_ptr)
>  {
> -	WRITE_ONCE(*count_ptr, READ_ONCE(*count_ptr) + 1);
> +	INC_ONCE(*count_ptr);
>  }
>  
>  static void update_session_stats(struct uds_request *request)
> diff --git a/fs/xfs/libxfs/xfs_iext_tree.c b/fs/xfs/libxfs/xfs_iext_tree.c
> index 8796f2b3e534..a1fcd4cf2424 100644
> --- a/fs/xfs/libxfs/xfs_iext_tree.c
> +++ b/fs/xfs/libxfs/xfs_iext_tree.c
> @@ -626,7 +626,7 @@ xfs_iext_realloc_root(
>   */
>  static inline void xfs_iext_inc_seq(struct xfs_ifork *ifp)
>  {
> -	WRITE_ONCE(ifp->if_seq, READ_ONCE(ifp->if_seq) + 1);
> +	INC_ONCE(ifp->if_seq);
>  }
>  
>  void
> diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
> index c9b58188ec61..77c253e29758 100644
> --- a/include/linux/compiler-gcc.h
> +++ b/include/linux/compiler-gcc.h
> @@ -137,3 +137,8 @@
>  #if GCC_VERSION < 90100
>  #undef __alloc_size__
>  #endif
> +
> +/*
> + * GCC can't properly optimize the real one with volatile on.
> + */
> +#define INC_ONCE(v) (v)++
> diff --git a/include/linux/compiler.h b/include/linux/compiler.h
> index efd43df3a99a..b1b13dac1b9e 100644
> --- a/include/linux/compiler.h
> +++ b/include/linux/compiler.h
> @@ -8,6 +8,10 @@
>  
>  #ifdef __KERNEL__
>  
> +#ifndef INC_ONCE
> +#define INC_ONCE(v)	(*(volatile typeof(v) *)&(v))++
> +#endif
> +
>  /*
>   * Note: DISABLE_BRANCH_PROFILING can be used by special lowlevel code
>   * to disable branch tracing on a per file basis.
> diff --git a/include/linux/rcupdate_trace.h b/include/linux/rcupdate_trace.h
> index e6c44eb428ab..adb12e7304da 100644
> --- a/include/linux/rcupdate_trace.h
> +++ b/include/linux/rcupdate_trace.h
> @@ -50,7 +50,7 @@ static inline void rcu_read_lock_trace(void)
>  {
>  	struct task_struct *t = current;
>  
> -	WRITE_ONCE(t->trc_reader_nesting, READ_ONCE(t->trc_reader_nesting) + 1);
> +	INC_ONCE(t->trc_reader_nesting);
>  	barrier();
>  	if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) &&
>  	    t->trc_reader_special.b.need_mb)
> diff --git a/include/linux/srcutiny.h b/include/linux/srcutiny.h
> index 1321da803274..bd4362323733 100644
> --- a/include/linux/srcutiny.h
> +++ b/include/linux/srcutiny.h
> @@ -66,7 +66,7 @@ static inline int __srcu_read_lock(struct srcu_struct *ssp)
>  
>  	preempt_disable();  // Needed for PREEMPT_AUTO
>  	idx = ((READ_ONCE(ssp->srcu_idx) + 1) & 0x2) >> 1;
> -	WRITE_ONCE(ssp->srcu_lock_nesting[idx], READ_ONCE(ssp->srcu_lock_nesting[idx]) + 1);
> +	INC_ONCE(ssp->srcu_lock_nesting[idx]);
>  	preempt_enable();
>  	return idx;
>  }
> diff --git a/io_uring/io_uring.c b/io_uring/io_uring.c
> index 06ff41484e29..ef3d4871e775 100644
> --- a/io_uring/io_uring.c
> +++ b/io_uring/io_uring.c
> @@ -373,7 +373,7 @@ static void io_account_cq_overflow(struct io_ring_ctx *ctx)
>  {
>  	struct io_rings *r = ctx->rings;
>  
> -	WRITE_ONCE(r->cq_overflow, READ_ONCE(r->cq_overflow) + 1);
> +	INC_ONCE(r->cq_overflow);
>  	ctx->cq_extra--;
>  }
>  
> diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
> index 5e2e53464794..a812af81dbff 100644
> --- a/kernel/rcu/srcutree.c
> +++ b/kernel/rcu/srcutree.c
> @@ -656,7 +656,7 @@ static unsigned long srcu_get_delay(struct srcu_struct *ssp)
>  			jbase += j - gpstart;
>  		if (!jbase) {
>  			ASSERT_EXCLUSIVE_WRITER(sup->srcu_n_exp_nodelay);
> -			WRITE_ONCE(sup->srcu_n_exp_nodelay, READ_ONCE(sup->srcu_n_exp_nodelay) + 1);
> +			INC_ONCE(sup->srcu_n_exp_nodelay);
>  			if (READ_ONCE(sup->srcu_n_exp_nodelay) > srcu_max_nodelay_phase)
>  				jbase = 1;
>  		}
> @@ -1856,7 +1856,7 @@ static void process_srcu(struct work_struct *work)
>  		j = jiffies;
>  		if (READ_ONCE(sup->reschedule_jiffies) == j) {
>  			ASSERT_EXCLUSIVE_WRITER(sup->reschedule_count);
> -			WRITE_ONCE(sup->reschedule_count, READ_ONCE(sup->reschedule_count) + 1);
> +			INC_ONCE(sup->reschedule_count);
>  			if (READ_ONCE(sup->reschedule_count) > srcu_max_nodelay)
>  				curdelay = 1;
>  		} else {
> diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
> index 3927ea5f7955..51f525089c27 100644
> --- a/kernel/rcu/tree_plugin.h
> +++ b/kernel/rcu/tree_plugin.h
> @@ -387,7 +387,7 @@ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp)
>  
>  static void rcu_preempt_read_enter(void)
>  {
> -	WRITE_ONCE(current->rcu_read_lock_nesting, READ_ONCE(current->rcu_read_lock_nesting) + 1);
> +	INC_ONCE(current->rcu_read_lock_nesting);
>  }
>  
>  static int rcu_preempt_read_exit(void)
> diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
> index f5329672815b..f0927407abbe 100644
> --- a/kernel/sched/fair.c
> +++ b/kernel/sched/fair.c
> @@ -3242,7 +3242,7 @@ static void reset_ptenuma_scan(struct task_struct *p)
>  	 * statistical sampling. Use READ_ONCE/WRITE_ONCE, which are not
>  	 * expensive, to avoid any form of compiler optimizations:
>  	 */
> -	WRITE_ONCE(p->mm->numa_scan_seq, READ_ONCE(p->mm->numa_scan_seq) + 1);
> +	INC_ONCE(p->mm->numa_scan_seq);
>  	p->mm->numa_scan_offset = 0;
>  }
>  
> diff --git a/mm/kfence/kfence_test.c b/mm/kfence/kfence_test.c
> index f65fb182466d..e0bf31b1875e 100644
> --- a/mm/kfence/kfence_test.c
> +++ b/mm/kfence/kfence_test.c
> @@ -517,7 +517,7 @@ static void test_kmalloc_aligned_oob_write(struct kunit *test)
>  	 * fault immediately after it.
>  	 */
>  	expect.addr = buf + size;
> -	WRITE_ONCE(*expect.addr, READ_ONCE(*expect.addr) + 1);
> +	INC_ONCE(*expect.addr);
>  	KUNIT_EXPECT_FALSE(test, report_available());
>  	test_free(buf);
>  	KUNIT_EXPECT_TRUE(test, report_matches(&expect));
> diff --git a/security/apparmor/apparmorfs.c b/security/apparmor/apparmorfs.c
> index 2c0185ebc900..63f5c8387764 100644
> --- a/security/apparmor/apparmorfs.c
> +++ b/security/apparmor/apparmorfs.c
> @@ -596,7 +596,7 @@ static __poll_t ns_revision_poll(struct file *file, poll_table *pt)
>  
>  void __aa_bump_ns_revision(struct aa_ns *ns)
>  {
> -	WRITE_ONCE(ns->revision, READ_ONCE(ns->revision) + 1);
> +	INC_ONCE(ns->revision);
>  	wake_up_interruptible(&ns->wait);
>  }
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.