Skip to content

Commit 93b5704

Browse files
committed
null_blk: add option for managing IO timeouts
Use the fault injection framework to provide a way for null_blk to configure timeouts. This only works for queue_mode 1 and 2, since the bio mode doesn't have code for tracking timeouts. Let's say you want to have a 10% chance of timing out every 100,000 requests, and for 5 total timeouts, you could do: modprobe null_blk timeout="100000,10,0,5" This is useful for adding blktests to test that IO timeouts are handled appropriately. Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent 8993d44 commit 93b5704

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

drivers/block/Kconfig

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ if BLK_DEV
1919
config BLK_DEV_NULL_BLK
2020
tristate "Null test block driver"
2121
select CONFIGFS_FS
22+
select FAULT_INJECTION
2223

2324
config BLK_DEV_FD
2425
tristate "Normal floppy disk support"

drivers/block/null_blk.c

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/hrtimer.h>
1515
#include <linux/configfs.h>
1616
#include <linux/badblocks.h>
17+
#include <linux/fault-inject.h>
1718

1819
#define SECTOR_SHIFT 9
1920
#define PAGE_SECTORS_SHIFT (PAGE_SHIFT - SECTOR_SHIFT)
@@ -26,6 +27,8 @@
2627
#define TICKS_PER_SEC 50ULL
2728
#define TIMER_INTERVAL (NSEC_PER_SEC / TICKS_PER_SEC)
2829

30+
static DECLARE_FAULT_ATTR(null_timeout_attr);
31+
2932
static inline u64 mb_per_tick(int mbps)
3033
{
3134
return (1 << 20) / TICKS_PER_SEC * ((u64) mbps);
@@ -162,6 +165,9 @@ static int g_home_node = NUMA_NO_NODE;
162165
module_param_named(home_node, g_home_node, int, S_IRUGO);
163166
MODULE_PARM_DESC(home_node, "Home node for the device");
164167

168+
static char g_timeout_str[80];
169+
module_param_string(timeout, g_timeout_str, sizeof(g_timeout_str), S_IRUGO);
170+
165171
static int g_queue_mode = NULL_Q_MQ;
166172

167173
static int null_param_store_val(const char *str, int *val, int min, int max)
@@ -1364,16 +1370,26 @@ static int null_rq_prep_fn(struct request_queue *q, struct request *req)
13641370
return BLKPREP_DEFER;
13651371
}
13661372

1373+
static bool should_timeout_request(struct request *rq)
1374+
{
1375+
if (g_timeout_str[0])
1376+
return should_fail(&null_timeout_attr, 1);
1377+
1378+
return false;
1379+
}
1380+
13671381
static void null_request_fn(struct request_queue *q)
13681382
{
13691383
struct request *rq;
13701384

13711385
while ((rq = blk_fetch_request(q)) != NULL) {
13721386
struct nullb_cmd *cmd = rq->special;
13731387

1374-
spin_unlock_irq(q->queue_lock);
1375-
null_handle_cmd(cmd);
1376-
spin_lock_irq(q->queue_lock);
1388+
if (!should_timeout_request(rq)) {
1389+
spin_unlock_irq(q->queue_lock);
1390+
null_handle_cmd(cmd);
1391+
spin_lock_irq(q->queue_lock);
1392+
}
13771393
}
13781394
}
13791395

@@ -1400,7 +1416,10 @@ static blk_status_t null_queue_rq(struct blk_mq_hw_ctx *hctx,
14001416

14011417
blk_mq_start_request(bd->rq);
14021418

1403-
return null_handle_cmd(cmd);
1419+
if (!should_timeout_request(bd->rq))
1420+
return null_handle_cmd(cmd);
1421+
1422+
return BLK_STS_OK;
14041423
}
14051424

14061425
static const struct blk_mq_ops null_mq_ops = {
@@ -1634,6 +1653,18 @@ static void null_validate_conf(struct nullb_device *dev)
16341653
dev->mbps = 0;
16351654
}
16361655

1656+
static bool null_setup_fault(void)
1657+
{
1658+
if (!g_timeout_str[0])
1659+
return true;
1660+
1661+
if (!setup_fault_attr(&null_timeout_attr, g_timeout_str))
1662+
return false;
1663+
1664+
null_timeout_attr.verbose = 0;
1665+
return true;
1666+
}
1667+
16371668
static int null_add_dev(struct nullb_device *dev)
16381669
{
16391670
struct nullb *nullb;
@@ -1667,6 +1698,9 @@ static int null_add_dev(struct nullb_device *dev)
16671698
if (rv)
16681699
goto out_cleanup_queues;
16691700

1701+
if (!null_setup_fault())
1702+
goto out_cleanup_queues;
1703+
16701704
nullb->tag_set->timeout = 5 * HZ;
16711705
nullb->q = blk_mq_init_queue(nullb->tag_set);
16721706
if (IS_ERR(nullb->q)) {
@@ -1691,6 +1725,10 @@ static int null_add_dev(struct nullb_device *dev)
16911725
rv = -ENOMEM;
16921726
goto out_cleanup_queues;
16931727
}
1728+
1729+
if (!null_setup_fault())
1730+
goto out_cleanup_blk_queue;
1731+
16941732
blk_queue_prep_rq(nullb->q, null_rq_prep_fn);
16951733
blk_queue_softirq_done(nullb->q, null_softirq_done_fn);
16961734
blk_queue_rq_timed_out(nullb->q, null_rq_timed_out_fn);

0 commit comments

Comments
 (0)