Skip to content

Commit 04b8b2f

Browse files
Christoph Hellwigkawasaki
authored andcommitted
RFC: use a TASK_FIFO kthread for read completion support
Commit 3fffb58 ("erofs: add per-cpu threads for decompression as an option") explains why workqueue aren't great for low-latency completion handling. Switch to a per-cpu kthread to handle it instead. This code is based on the erofs code in the above commit, but further simplified by directly using a kthread instead of a kthread_work. Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 8d412f4 commit 04b8b2f

1 file changed

Lines changed: 65 additions & 52 deletions

File tree

block/bio.c

Lines changed: 65 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include <linux/blk-crypto.h>
2020
#include <linux/xarray.h>
2121
#include <linux/kmemleak.h>
22-
#include <linux/llist.h>
22+
#include <linux/freezer.h>
2323

2424
#include <trace/events/block.h>
2525
#include "blk.h"
@@ -1718,51 +1718,83 @@ void bio_check_pages_dirty(struct bio *bio)
17181718
EXPORT_SYMBOL_GPL(bio_check_pages_dirty);
17191719

17201720
struct bio_complete_batch {
1721-
struct llist_head list;
1722-
struct delayed_work work;
1723-
int cpu;
1721+
spinlock_t lock;
1722+
struct bio_list bios;
1723+
struct task_struct *worker;
17241724
};
17251725

17261726
static DEFINE_PER_CPU(struct bio_complete_batch, bio_complete_batch);
1727-
static struct workqueue_struct *bio_complete_wq;
17281727

1729-
static void bio_complete_work_fn(struct work_struct *w)
1728+
static bool bio_try_complete_batch(struct bio_complete_batch *batch)
17301729
{
1731-
struct delayed_work *dw = to_delayed_work(w);
1732-
struct bio_complete_batch *batch =
1733-
container_of(dw, struct bio_complete_batch, work);
1734-
struct llist_node *node;
1735-
struct bio *bio, *next;
1730+
struct bio_list bios;
1731+
unsigned long flags;
1732+
struct bio *bio;
17361733

1737-
do {
1738-
node = llist_del_all(&batch->list);
1739-
if (!node)
1740-
break;
1734+
spin_lock_irqsave(&batch->lock, flags);
1735+
bios = batch->bios;
1736+
bio_list_init(&batch->bios);
1737+
spin_unlock_irqrestore(&batch->lock, flags);
17411738

1742-
node = llist_reverse_order(node);
1743-
llist_for_each_entry_safe(bio, next, node, bi_llist)
1744-
bio->bi_end_io(bio);
1739+
if (bio_list_empty(&bios))
1740+
return false;
17451741

1746-
if (need_resched()) {
1747-
if (!llist_empty(&batch->list))
1748-
mod_delayed_work_on(batch->cpu,
1749-
bio_complete_wq,
1750-
&batch->work, 0);
1751-
break;
1752-
}
1753-
} while (1);
1742+
__set_current_state(TASK_RUNNING);
1743+
while ((bio = bio_list_pop(&bios)))
1744+
bio->bi_end_io(bio);
1745+
return true;
1746+
}
1747+
1748+
static int bio_complete_thread(void *private)
1749+
{
1750+
struct bio_complete_batch *batch = private;
1751+
1752+
for (;;) {
1753+
set_current_state(TASK_INTERRUPTIBLE);
1754+
if (!bio_try_complete_batch(batch))
1755+
schedule();
1756+
}
1757+
1758+
return 0;
17541759
}
17551760

17561761
void __bio_complete_in_task(struct bio *bio)
17571762
{
1758-
struct bio_complete_batch *batch = this_cpu_ptr(&bio_complete_batch);
1763+
struct bio_complete_batch *batch;
1764+
unsigned long flags;
1765+
bool wake;
1766+
1767+
get_cpu();
1768+
batch = this_cpu_ptr(&bio_complete_batch);
1769+
spin_lock_irqsave(&batch->lock, flags);
1770+
wake = bio_list_empty(&batch->bios);
1771+
bio_list_add(&batch->bios, bio);
1772+
spin_unlock_irqrestore(&batch->lock, flags);
1773+
put_cpu();
17591774

1760-
if (llist_add(&bio->bi_llist, &batch->list))
1761-
mod_delayed_work_on(batch->cpu, bio_complete_wq,
1762-
&batch->work, 1);
1775+
if (wake)
1776+
wake_up_process(batch->worker);
17631777
}
17641778
EXPORT_SYMBOL_GPL(__bio_complete_in_task);
17651779

1780+
static void __init bio_complete_batch_init(int cpu)
1781+
{
1782+
struct bio_complete_batch *batch =
1783+
per_cpu_ptr(&bio_complete_batch, cpu);
1784+
struct task_struct *worker;
1785+
1786+
worker = kthread_create_on_cpu(bio_complete_thread,
1787+
per_cpu_ptr(&bio_complete_batch, cpu),
1788+
cpu, "bio_worker/%u");
1789+
if (IS_ERR(worker))
1790+
panic("bio: can't create kthread_work");
1791+
sched_set_fifo_low(worker);
1792+
1793+
spin_lock_init(&batch->lock);
1794+
bio_list_init(&batch->bios);
1795+
batch->worker = worker;
1796+
}
1797+
17661798
static inline bool bio_remaining_done(struct bio *bio)
17671799
{
17681800
/*
@@ -2028,16 +2060,7 @@ EXPORT_SYMBOL(bioset_init);
20282060
*/
20292061
static int bio_complete_batch_cpu_dead(unsigned int cpu)
20302062
{
2031-
struct bio_complete_batch *batch =
2032-
per_cpu_ptr(&bio_complete_batch, cpu);
2033-
struct llist_node *node;
2034-
struct bio *bio, *next;
2035-
2036-
node = llist_del_all(&batch->list);
2037-
node = llist_reverse_order(node);
2038-
llist_for_each_entry_safe(bio, next, node, bi_llist)
2039-
bio->bi_end_io(bio);
2040-
2063+
bio_try_complete_batch(per_cpu_ptr(&bio_complete_batch, cpu));
20412064
return 0;
20422065
}
20432066

@@ -2055,18 +2078,8 @@ static int __init init_bio(void)
20552078
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
20562079
}
20572080

2058-
for_each_possible_cpu(i) {
2059-
struct bio_complete_batch *batch =
2060-
per_cpu_ptr(&bio_complete_batch, i);
2061-
2062-
init_llist_head(&batch->list);
2063-
INIT_DELAYED_WORK(&batch->work, bio_complete_work_fn);
2064-
batch->cpu = i;
2065-
}
2066-
2067-
bio_complete_wq = alloc_workqueue("bio_complete", WQ_MEM_RECLAIM, 0);
2068-
if (!bio_complete_wq)
2069-
panic("bio: can't allocate bio_complete workqueue\n");
2081+
for_each_possible_cpu(i)
2082+
bio_complete_batch_init(i);
20702083

20712084
cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "block/bio:complete:dead",
20722085
NULL, bio_complete_batch_cpu_dead);

0 commit comments

Comments
 (0)