io-wq: max_worker fixes
authorPavel Begunkov <asml.silence@gmail.com>
Tue, 19 Oct 2021 19:31:26 +0000 (20:31 +0100)
committerJens Axboe <axboe@kernel.dk>
Tue, 19 Oct 2021 23:09:34 +0000 (17:09 -0600)
First, fix nr_workers checks against max_workers, with max_worker
registration, it may pretty easily happen that nr_workers > max_workers.

Also, synchronise writing to acct->max_worker with wqe->lock. It's not
an actual problem, but as we don't care about io_wqe_create_worker(),
it's better than WRITE_ONCE()/READ_ONCE().

Fixes: 2e480058ddc2 ("io-wq: provide a way to limit max number of workers")
Reported-by: Beld Zhang <beldzhang@gmail.com>
Signed-off-by: Pavel Begunkov <asml.silence@gmail.com>
Link: https://lore.kernel.org/r/11f90e6b49410b7d1a88f5d04fb8d95bb86b8cf3.1634671835.git.asml.silence@gmail.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
fs/io-wq.c

index 5bf8aa8..422a7ed 100644 (file)
@@ -253,7 +253,7 @@ static bool io_wqe_create_worker(struct io_wqe *wqe, struct io_wqe_acct *acct)
                pr_warn_once("io-wq is not configured for unbound workers");
 
        raw_spin_lock(&wqe->lock);
-       if (acct->nr_workers == acct->max_workers) {
+       if (acct->nr_workers >= acct->max_workers) {
                raw_spin_unlock(&wqe->lock);
                return true;
        }
@@ -1291,15 +1291,18 @@ int io_wq_max_workers(struct io_wq *wq, int *new_count)
 
        rcu_read_lock();
        for_each_node(node) {
+               struct io_wqe *wqe = wq->wqes[node];
                struct io_wqe_acct *acct;
 
+               raw_spin_lock(&wqe->lock);
                for (i = 0; i < IO_WQ_ACCT_NR; i++) {
-                       acct = &wq->wqes[node]->acct[i];
+                       acct = &wqe->acct[i];
                        prev = max_t(int, acct->max_workers, prev);
                        if (new_count[i])
                                acct->max_workers = new_count[i];
                        new_count[i] = prev;
                }
+               raw_spin_unlock(&wqe->lock);
        }
        rcu_read_unlock();
        return 0;