Skip to content

Commit b5542ab

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 5f5fe64 commit b5542ab

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"
@@ -1719,51 +1719,83 @@ void bio_check_pages_dirty(struct bio *bio)
17191719
EXPORT_SYMBOL_GPL(bio_check_pages_dirty);
17201720

17211721
struct bio_complete_batch {
1722-
struct llist_head list;
1723-
struct delayed_work work;
1724-
int cpu;
1722+
spinlock_t lock;
1723+
struct bio_list bios;
1724+
struct task_struct *worker;
17251725
};
17261726

17271727
static DEFINE_PER_CPU(struct bio_complete_batch, bio_complete_batch);
1728-
static struct workqueue_struct *bio_complete_wq;
17291728

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

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

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

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

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

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

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

@@ -2056,18 +2079,8 @@ static int __init init_bio(void)
20562079
SLAB_HWCACHE_ALIGN | SLAB_PANIC, NULL);
20572080
}
20582081

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

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

0 commit comments

Comments
 (0)