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
>
next prev parent 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