All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
To: Tejun Heo <tj@kernel.org>
Cc: torvalds@linux-foundation.org, jannh@google.com, bcrl@kvack.org,
	viro@zeniv.linux.org.uk, kent.overstreet@gmail.com,
	security@kernel.org, linux-kernel@vger.kernel.org,
	kernel-team@fb.com
Subject: Re: [PATCH 6/8] RCU, workqueue: Implement rcu_work
Date: Wed, 14 Mar 2018 13:13:04 -0700	[thread overview]
Message-ID: <20180314201304.GF3918@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180314194515.1661824-6-tj@kernel.org>

On Wed, Mar 14, 2018 at 12:45:13PM -0700, Tejun Heo wrote:
> There are cases where RCU callback needs to be bounced to a sleepable
> context.  This is currently done by the RCU callback queueing a work
> item, which can be cumbersome to write and confusing to read.
> 
> This patch introduces rcu_work, a workqueue work variant which gets
> executed after a RCU grace period, and converts the open coded
> bouncing in fs/aio and kernel/cgroup.
> 
> v3: Dropped queue_rcu_work_on().  Documented rcu grace period behavior
>     after queue_rcu_work().
> 
> v2: Use rcu_barrier() instead of synchronize_rcu() to wait for
>     completion of previously queued rcu callback as per Paul.
> 
> Signed-off-by: Tejun Heo <tj@kernel.org>
> Cc: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>

Looks good to me!

Reviewed-by: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>

> Cc: Linus Torvalds <torvalds@linux-foundation.org>
> ---
>  include/linux/workqueue.h | 23 ++++++++++++++++++++
>  kernel/workqueue.c        | 54 +++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 77 insertions(+)
> 
> diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
> index bc0cda1..d026f8f 100644
> --- a/include/linux/workqueue.h
> +++ b/include/linux/workqueue.h
> @@ -13,6 +13,7 @@
>  #include <linux/threads.h>
>  #include <linux/atomic.h>
>  #include <linux/cpumask.h>
> +#include <linux/rcupdate.h>
> 
>  struct workqueue_struct;
> 
> @@ -120,6 +121,14 @@ struct delayed_work {
>  	int cpu;
>  };
> 
> +struct rcu_work {
> +	struct work_struct work;
> +	struct rcu_head rcu;
> +
> +	/* target workqueue ->rcu uses to queue ->work */
> +	struct workqueue_struct *wq;
> +};
> +
>  /**
>   * struct workqueue_attrs - A struct for workqueue attributes.
>   *
> @@ -151,6 +160,11 @@ static inline struct delayed_work *to_delayed_work(struct work_struct *work)
>  	return container_of(work, struct delayed_work, work);
>  }
> 
> +static inline struct rcu_work *to_rcu_work(struct work_struct *work)
> +{
> +	return container_of(work, struct rcu_work, work);
> +}
> +
>  struct execute_work {
>  	struct work_struct work;
>  };
> @@ -266,6 +280,12 @@ static inline unsigned int work_static(struct work_struct *work) { return 0; }
>  #define INIT_DEFERRABLE_WORK_ONSTACK(_work, _func)			\
>  	__INIT_DELAYED_WORK_ONSTACK(_work, _func, TIMER_DEFERRABLE)
> 
> +#define INIT_RCU_WORK(_work, _func)					\
> +	INIT_WORK(&(_work)->work, (_func))
> +
> +#define INIT_RCU_WORK_ONSTACK(_work, _func)				\
> +	INIT_WORK_ONSTACK(&(_work)->work, (_func))
> +
>  /**
>   * work_pending - Find out whether a work item is currently pending
>   * @work: The work item in question
> @@ -447,6 +467,7 @@ extern bool queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
>  			struct delayed_work *work, unsigned long delay);
>  extern bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
>  			struct delayed_work *dwork, unsigned long delay);
> +extern bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork);
> 
>  extern void flush_workqueue(struct workqueue_struct *wq);
>  extern void drain_workqueue(struct workqueue_struct *wq);
> @@ -463,6 +484,8 @@ extern bool flush_delayed_work(struct delayed_work *dwork);
>  extern bool cancel_delayed_work(struct delayed_work *dwork);
>  extern bool cancel_delayed_work_sync(struct delayed_work *dwork);
> 
> +extern bool flush_rcu_work(struct rcu_work *rwork);
> +
>  extern void workqueue_set_max_active(struct workqueue_struct *wq,
>  				     int max_active);
>  extern struct work_struct *current_work(void);
> diff --git a/kernel/workqueue.c b/kernel/workqueue.c
> index bb9a519..7df85fa 100644
> --- a/kernel/workqueue.c
> +++ b/kernel/workqueue.c
> @@ -1604,6 +1604,40 @@ bool mod_delayed_work_on(int cpu, struct workqueue_struct *wq,
>  }
>  EXPORT_SYMBOL_GPL(mod_delayed_work_on);
> 
> +static void rcu_work_rcufn(struct rcu_head *rcu)
> +{
> +	struct rcu_work *rwork = container_of(rcu, struct rcu_work, rcu);
> +
> +	/* read the comment in __queue_work() */
> +	local_irq_disable();
> +	__queue_work(WORK_CPU_UNBOUND, rwork->wq, &rwork->work);
> +	local_irq_enable();
> +}
> +
> +/**
> + * queue_rcu_work - queue work after a RCU grace period
> + * @wq: workqueue to use
> + * @rwork: work to queue
> + *
> + * Return: %false if @rwork was already pending, %true otherwise.  Note
> + * that a full RCU grace period is guaranteed only after a %true return.
> + * While @rwork is guarnateed to be executed after a %false return, the
> + * execution may happen before a full RCU grace period has passed.
> + */
> +bool queue_rcu_work(struct workqueue_struct *wq, struct rcu_work *rwork)
> +{
> +	struct work_struct *work = &rwork->work;
> +
> +	if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
> +		rwork->wq = wq;
> +		call_rcu(&rwork->rcu, rcu_work_rcufn);
> +		return true;
> +	}
> +
> +	return false;
> +}
> +EXPORT_SYMBOL(queue_rcu_work);
> +
>  /**
>   * worker_enter_idle - enter idle state
>   * @worker: worker which is entering idle state
> @@ -3001,6 +3035,26 @@ bool flush_delayed_work(struct delayed_work *dwork)
>  }
>  EXPORT_SYMBOL(flush_delayed_work);
> 
> +/**
> + * flush_rcu_work - wait for a rwork to finish executing the last queueing
> + * @rwork: the rcu work to flush
> + *
> + * Return:
> + * %true if flush_rcu_work() waited for the work to finish execution,
> + * %false if it was already idle.
> + */
> +bool flush_rcu_work(struct rcu_work *rwork)
> +{
> +	if (test_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(&rwork->work))) {
> +		rcu_barrier();
> +		flush_work(&rwork->work);
> +		return true;
> +	} else {
> +		return flush_work(&rwork->work);
> +	}
> +}
> +EXPORT_SYMBOL(flush_rcu_work);
> +
>  static bool __cancel_work(struct work_struct *work, bool is_dwork)
>  {
>  	unsigned long flags;
> -- 
> 2.9.5
> 

  reply	other threads:[~2018-03-14 20:13 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-03-14 19:41 [PATCHSET v2] percpu_ref, RCU: Audit RCU usages in percpu_ref users Tejun Heo
2018-03-14 19:45 ` [PATCH 1/8] fs/aio: Add explicit RCU grace period when freeing kioctx Tejun Heo
2018-03-14 19:45   ` [PATCH 2/8] fs/aio: Use RCU accessors for kioctx_table->table[] Tejun Heo
2018-03-14 19:45   ` [PATCH 3/8] RDMAVT: Fix synchronization around percpu_ref Tejun Heo
2018-03-15 22:24     ` Jason Gunthorpe
2018-03-14 19:45   ` [PATCH 4/8] HMM: Remove superflous RCU protection around radix tree lookup Tejun Heo
2018-03-14 19:45     ` Tejun Heo
2018-03-26 14:54     ` Tejun Heo
2018-03-26 14:54       ` Tejun Heo
2018-03-27 16:12       ` Jerome Glisse
2018-03-27 16:12         ` Jerome Glisse
2018-03-14 19:45   ` [PATCH 5/8] percpu_ref: Update doc to dissuade users from depending on internal RCU grace periods Tejun Heo
2018-03-19 17:10     ` Tejun Heo
2018-03-14 19:45   ` [PATCH 6/8] RCU, workqueue: Implement rcu_work Tejun Heo
2018-03-14 20:13     ` Paul E. McKenney [this message]
2018-03-16  6:01     ` Lai Jiangshan
2018-03-19 16:45       ` Tejun Heo
2018-03-20 10:04         ` Lai Jiangshan
2018-03-14 19:45   ` [PATCH 7/8] cgroup: Use rcu_work instead of explicit rcu and work item Tejun Heo
2018-03-14 19:45   ` [PATCH 8/8] fs/aio: " Tejun Heo
2018-03-19 17:12     ` Tejun Heo
2018-03-21 15:58     ` Oleg Nesterov
2018-03-21 16:40       ` Tejun Heo
2018-03-21 17:17         ` Oleg Nesterov
2018-03-21 17:53           ` Tejun Heo
2018-03-22 11:24             ` Oleg Nesterov
2018-03-26 15:04               ` Tejun Heo
2018-03-27 14:28                 ` Oleg Nesterov
2018-03-27 15:55                   ` Tejun Heo
2018-03-29 16:49                     ` Oleg Nesterov
2018-03-29 17:41                       ` Tejun Heo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20180314201304.GF3918@linux.vnet.ibm.com \
    --to=paulmck@linux.vnet.ibm.com \
    --cc=bcrl@kvack.org \
    --cc=jannh@google.com \
    --cc=kent.overstreet@gmail.com \
    --cc=kernel-team@fb.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=security@kernel.org \
    --cc=tj@kernel.org \
    --cc=torvalds@linux-foundation.org \
    --cc=viro@zeniv.linux.org.uk \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.