public inbox for [email protected]
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <[email protected]>
To: Jens Axboe <[email protected]>
Cc: [email protected]
Subject: Re: [PATCH 3/3] io-wq: ensure free/busy list browsing see all items
Date: Wed, 13 Nov 2019 15:42:51 -0800	[thread overview]
Message-ID: <20191113234251.GH2865@paulmck-ThinkPad-P72> (raw)
In-Reply-To: <[email protected]>

On Wed, Nov 13, 2019 at 02:32:06PM -0700, Jens Axboe wrote:
> We have two lists for workers in io-wq, a busy and a free list. For
> certain operations we want to browse all workers, and we currently do
> that by browsing the two separate lists. But since these lists are RCU
> protected, we can potentially miss workers if they move between the two
> lists while we're browsing them.
> 
> Add a third list, all_list, that simply holds all workers. A worker is
> added to that list when it starts, and removed when it exits. This makes
> the worker iteration cleaner, too.
> 
> Reported-by: Paul E. McKenney <[email protected]>
> Signed-off-by: Jens Axboe <[email protected]>

H/T to Olof for asking the question, by the way!

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

> ---
>  fs/io-wq.c | 41 +++++++++++------------------------------
>  1 file changed, 11 insertions(+), 30 deletions(-)
> 
> diff --git a/fs/io-wq.c b/fs/io-wq.c
> index 4031b75541be..fcb6c74209da 100644
> --- a/fs/io-wq.c
> +++ b/fs/io-wq.c
> @@ -46,6 +46,7 @@ struct io_worker {
>  	refcount_t ref;
>  	unsigned flags;
>  	struct hlist_nulls_node nulls_node;
> +	struct list_head all_list;
>  	struct task_struct *task;
>  	wait_queue_head_t wait;
>  	struct io_wqe *wqe;
> @@ -96,6 +97,7 @@ struct io_wqe {
>  
>  	struct io_wq_nulls_list free_list;
>  	struct io_wq_nulls_list busy_list;
> +	struct list_head all_list;
>  
>  	struct io_wq *wq;
>  };
> @@ -212,6 +214,7 @@ static void io_worker_exit(struct io_worker *worker)
>  
>  	spin_lock_irq(&wqe->lock);
>  	hlist_nulls_del_rcu(&worker->nulls_node);
> +	list_del_rcu(&worker->all_list);
>  	if (__io_worker_unuse(wqe, worker)) {
>  		__release(&wqe->lock);
>  		spin_lock_irq(&wqe->lock);
> @@ -590,6 +593,7 @@ static void create_io_worker(struct io_wq *wq, struct io_wqe *wqe, int index)
>  
>  	spin_lock_irq(&wqe->lock);
>  	hlist_nulls_add_head_rcu(&worker->nulls_node, &wqe->free_list.head);
> +	list_add_tail_rcu(&worker->all_list, &wqe->all_list);
>  	worker->flags |= IO_WORKER_F_FREE;
>  	if (index == IO_WQ_ACCT_BOUND)
>  		worker->flags |= IO_WORKER_F_BOUND;
> @@ -733,16 +737,13 @@ static bool io_wqe_worker_send_sig(struct io_worker *worker, void *data)
>   * worker that isn't exiting
>   */
>  static bool io_wq_for_each_worker(struct io_wqe *wqe,
> -				  struct io_wq_nulls_list *list,
>  				  bool (*func)(struct io_worker *, void *),
>  				  void *data)
>  {
> -	struct hlist_nulls_node *n;
>  	struct io_worker *worker;
>  	bool ret = false;
>  
> -restart:
> -	hlist_nulls_for_each_entry_rcu(worker, n, &list->head, nulls_node) {
> +	list_for_each_entry_rcu(worker, &wqe->all_list, all_list) {
>  		if (io_worker_get(worker)) {
>  			ret = func(worker, data);
>  			io_worker_release(worker);
> @@ -750,8 +751,7 @@ static bool io_wq_for_each_worker(struct io_wqe *wqe,
>  				break;
>  		}
>  	}
> -	if (!ret && get_nulls_value(n) != list->nulls)
> -		goto restart;
> +
>  	return ret;
>  }
>  
> @@ -769,10 +769,7 @@ void io_wq_cancel_all(struct io_wq *wq)
>  	for (i = 0; i < wq->nr_wqes; i++) {
>  		struct io_wqe *wqe = wq->wqes[i];
>  
> -		io_wq_for_each_worker(wqe, &wqe->busy_list,
> -					io_wqe_worker_send_sig, NULL);
> -		io_wq_for_each_worker(wqe, &wqe->free_list,
> -					io_wqe_worker_send_sig, NULL);
> +		io_wq_for_each_worker(wqe, io_wqe_worker_send_sig, NULL);
>  	}
>  	rcu_read_unlock();
>  }
> @@ -834,14 +831,7 @@ static enum io_wq_cancel io_wqe_cancel_cb_work(struct io_wqe *wqe,
>  	}
>  
>  	rcu_read_lock();
> -	found = io_wq_for_each_worker(wqe, &wqe->free_list, io_work_cancel,
> -					&data);
> -	if (found)
> -		goto done;
> -
> -	found = io_wq_for_each_worker(wqe, &wqe->busy_list, io_work_cancel,
> -					&data);
> -done:
> +	found = io_wq_for_each_worker(wqe, io_work_cancel, &data);
>  	rcu_read_unlock();
>  	return found ? IO_WQ_CANCEL_RUNNING : IO_WQ_CANCEL_NOTFOUND;
>  }
> @@ -919,14 +909,7 @@ static enum io_wq_cancel io_wqe_cancel_work(struct io_wqe *wqe,
>  	 * completion will run normally in this case.
>  	 */
>  	rcu_read_lock();
> -	found = io_wq_for_each_worker(wqe, &wqe->free_list, io_wq_worker_cancel,
> -					cwork);
> -	if (found)
> -		goto done;
> -
> -	found = io_wq_for_each_worker(wqe, &wqe->busy_list, io_wq_worker_cancel,
> -					cwork);
> -done:
> +	found = io_wq_for_each_worker(wqe, io_wq_worker_cancel, cwork);
>  	rcu_read_unlock();
>  	return found ? IO_WQ_CANCEL_RUNNING : IO_WQ_CANCEL_NOTFOUND;
>  }
> @@ -1030,6 +1013,7 @@ struct io_wq *io_wq_create(unsigned bounded, struct mm_struct *mm,
>  		wqe->free_list.nulls = 0;
>  		INIT_HLIST_NULLS_HEAD(&wqe->busy_list.head, 1);
>  		wqe->busy_list.nulls = 1;
> +		INIT_LIST_HEAD(&wqe->all_list);
>  
>  		i++;
>  	}
> @@ -1077,10 +1061,7 @@ void io_wq_destroy(struct io_wq *wq)
>  
>  		if (!wqe)
>  			continue;
> -		io_wq_for_each_worker(wqe, &wqe->free_list, io_wq_worker_wake,
> -						NULL);
> -		io_wq_for_each_worker(wqe, &wqe->busy_list, io_wq_worker_wake,
> -						NULL);
> +		io_wq_for_each_worker(wqe, io_wq_worker_wake, NULL);
>  	}
>  	rcu_read_unlock();
>  
> -- 
> 2.24.0
> 

  reply	other threads:[~2019-11-13 23:42 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-11-13 21:32 [PATCHSET v2] Improve io_uring cancellations Jens Axboe
2019-11-13 21:32 ` [PATCH 1/3] io_wq: add get/put_work handlers to io_wq_create() Jens Axboe
2019-11-13 21:32 ` [PATCH 2/3] io-wq: ensure we have a stable view of ->cur_work for cancellations Jens Axboe
2019-11-13 21:32 ` [PATCH 3/3] io-wq: ensure free/busy list browsing see all items Jens Axboe
2019-11-13 23:42   ` Paul E. McKenney [this message]
2019-11-14  2:51     ` Jens Axboe

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=20191113234251.GH2865@paulmck-ThinkPad-P72 \
    [email protected] \
    [email protected] \
    [email protected] \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox