xref: /kernel/linux/linux-6.6/block/blk-timeout.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Functions related to generic timeout handling of requests.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci#include <linux/kernel.h>
662306a36Sopenharmony_ci#include <linux/module.h>
762306a36Sopenharmony_ci#include <linux/blkdev.h>
862306a36Sopenharmony_ci#include <linux/fault-inject.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "blk.h"
1162306a36Sopenharmony_ci#include "blk-mq.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#ifdef CONFIG_FAIL_IO_TIMEOUT
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic DECLARE_FAULT_ATTR(fail_io_timeout);
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic int __init setup_fail_io_timeout(char *str)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	return setup_fault_attr(&fail_io_timeout, str);
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci__setup("fail_io_timeout=", setup_fail_io_timeout);
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cibool __blk_should_fake_timeout(struct request_queue *q)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	return should_fail(&fail_io_timeout, 1);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__blk_should_fake_timeout);
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistatic int __init fail_io_timeout_debugfs(void)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	struct dentry *dir = fault_create_debugfs_attr("fail_io_timeout",
3262306a36Sopenharmony_ci						NULL, &fail_io_timeout);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(dir);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cilate_initcall(fail_io_timeout_debugfs);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cissize_t part_timeout_show(struct device *dev, struct device_attribute *attr,
4062306a36Sopenharmony_ci			  char *buf)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	struct gendisk *disk = dev_to_disk(dev);
4362306a36Sopenharmony_ci	int set = test_bit(QUEUE_FLAG_FAIL_IO, &disk->queue->queue_flags);
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	return sprintf(buf, "%d\n", set != 0);
4662306a36Sopenharmony_ci}
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_cissize_t part_timeout_store(struct device *dev, struct device_attribute *attr,
4962306a36Sopenharmony_ci			   const char *buf, size_t count)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct gendisk *disk = dev_to_disk(dev);
5262306a36Sopenharmony_ci	int val;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	if (count) {
5562306a36Sopenharmony_ci		struct request_queue *q = disk->queue;
5662306a36Sopenharmony_ci		char *p = (char *) buf;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci		val = simple_strtoul(p, &p, 10);
5962306a36Sopenharmony_ci		if (val)
6062306a36Sopenharmony_ci			blk_queue_flag_set(QUEUE_FLAG_FAIL_IO, q);
6162306a36Sopenharmony_ci		else
6262306a36Sopenharmony_ci			blk_queue_flag_clear(QUEUE_FLAG_FAIL_IO, q);
6362306a36Sopenharmony_ci	}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	return count;
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#endif /* CONFIG_FAIL_IO_TIMEOUT */
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/**
7162306a36Sopenharmony_ci * blk_abort_request - Request recovery for the specified command
7262306a36Sopenharmony_ci * @req:	pointer to the request of interest
7362306a36Sopenharmony_ci *
7462306a36Sopenharmony_ci * This function requests that the block layer start recovery for the
7562306a36Sopenharmony_ci * request by deleting the timer and calling the q's timeout function.
7662306a36Sopenharmony_ci * LLDDs who implement their own error recovery MAY ignore the timeout
7762306a36Sopenharmony_ci * event if they generated blk_abort_request.
7862306a36Sopenharmony_ci */
7962306a36Sopenharmony_civoid blk_abort_request(struct request *req)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	/*
8262306a36Sopenharmony_ci	 * All we need to ensure is that timeout scan takes place
8362306a36Sopenharmony_ci	 * immediately and that scan sees the new timeout value.
8462306a36Sopenharmony_ci	 * No need for fancy synchronizations.
8562306a36Sopenharmony_ci	 */
8662306a36Sopenharmony_ci	WRITE_ONCE(req->deadline, jiffies);
8762306a36Sopenharmony_ci	kblockd_schedule_work(&req->q->timeout_work);
8862306a36Sopenharmony_ci}
8962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(blk_abort_request);
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic unsigned long blk_timeout_mask __read_mostly;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic int __init blk_timeout_init(void)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	blk_timeout_mask = roundup_pow_of_two(HZ) - 1;
9662306a36Sopenharmony_ci	return 0;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_cilate_initcall(blk_timeout_init);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci/*
10262306a36Sopenharmony_ci * Just a rough estimate, we don't care about specific values for timeouts.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cistatic inline unsigned long blk_round_jiffies(unsigned long j)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	return (j + blk_timeout_mask) + 1;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ciunsigned long blk_rq_timeout(unsigned long timeout)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	unsigned long maxt;
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	maxt = blk_round_jiffies(jiffies + BLK_MAX_TIMEOUT);
11462306a36Sopenharmony_ci	if (time_after(timeout, maxt))
11562306a36Sopenharmony_ci		timeout = maxt;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	return timeout;
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci/**
12162306a36Sopenharmony_ci * blk_add_timer - Start timeout timer for a single request
12262306a36Sopenharmony_ci * @req:	request that is about to start running.
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * Notes:
12562306a36Sopenharmony_ci *    Each request has its own timer, and as it is added to the queue, we
12662306a36Sopenharmony_ci *    set up the timer. When the request completes, we cancel the timer.
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_civoid blk_add_timer(struct request *req)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct request_queue *q = req->q;
13162306a36Sopenharmony_ci	unsigned long expiry;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	/*
13462306a36Sopenharmony_ci	 * Some LLDs, like scsi, peek at the timeout to prevent a
13562306a36Sopenharmony_ci	 * command from being retried forever.
13662306a36Sopenharmony_ci	 */
13762306a36Sopenharmony_ci	if (!req->timeout)
13862306a36Sopenharmony_ci		req->timeout = q->rq_timeout;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	req->rq_flags &= ~RQF_TIMED_OUT;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	expiry = jiffies + req->timeout;
14362306a36Sopenharmony_ci	WRITE_ONCE(req->deadline, expiry);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	/*
14662306a36Sopenharmony_ci	 * If the timer isn't already pending or this timeout is earlier
14762306a36Sopenharmony_ci	 * than an existing one, modify the timer. Round up to next nearest
14862306a36Sopenharmony_ci	 * second.
14962306a36Sopenharmony_ci	 */
15062306a36Sopenharmony_ci	expiry = blk_rq_timeout(blk_round_jiffies(expiry));
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	if (!timer_pending(&q->timeout) ||
15362306a36Sopenharmony_ci	    time_before(expiry, q->timeout.expires)) {
15462306a36Sopenharmony_ci		unsigned long diff = q->timeout.expires - expiry;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci		/*
15762306a36Sopenharmony_ci		 * Due to added timer slack to group timers, the timer
15862306a36Sopenharmony_ci		 * will often be a little in front of what we asked for.
15962306a36Sopenharmony_ci		 * So apply some tolerance here too, otherwise we keep
16062306a36Sopenharmony_ci		 * modifying the timer because expires for value X
16162306a36Sopenharmony_ci		 * will be X + something.
16262306a36Sopenharmony_ci		 */
16362306a36Sopenharmony_ci		if (!timer_pending(&q->timeout) || (diff >= HZ / 2))
16462306a36Sopenharmony_ci			mod_timer(&q->timeout, expiry);
16562306a36Sopenharmony_ci	}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci}
168