162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MQ Deadline i/o scheduler - adaptation of the legacy deadline scheduler, 462306a36Sopenharmony_ci * for the blk-mq scheduling framework 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2016 Jens Axboe <axboe@kernel.dk> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/blkdev.h> 1162306a36Sopenharmony_ci#include <linux/bio.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/slab.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/compiler.h> 1662306a36Sopenharmony_ci#include <linux/rbtree.h> 1762306a36Sopenharmony_ci#include <linux/sbitmap.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <trace/events/block.h> 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include "elevator.h" 2262306a36Sopenharmony_ci#include "blk.h" 2362306a36Sopenharmony_ci#include "blk-mq.h" 2462306a36Sopenharmony_ci#include "blk-mq-debugfs.h" 2562306a36Sopenharmony_ci#include "blk-mq-sched.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci/* 2862306a36Sopenharmony_ci * See Documentation/block/deadline-iosched.rst 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_cistatic const int read_expire = HZ / 2; /* max time before a read is submitted. */ 3162306a36Sopenharmony_cistatic const int write_expire = 5 * HZ; /* ditto for writes, these limits are SOFT! */ 3262306a36Sopenharmony_ci/* 3362306a36Sopenharmony_ci * Time after which to dispatch lower priority requests even if higher 3462306a36Sopenharmony_ci * priority requests are pending. 3562306a36Sopenharmony_ci */ 3662306a36Sopenharmony_cistatic const int prio_aging_expire = 10 * HZ; 3762306a36Sopenharmony_cistatic const int writes_starved = 2; /* max times reads can starve a write */ 3862306a36Sopenharmony_cistatic const int fifo_batch = 16; /* # of sequential requests treated as one 3962306a36Sopenharmony_ci by the above parameters. For throughput. */ 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cienum dd_data_dir { 4262306a36Sopenharmony_ci DD_READ = READ, 4362306a36Sopenharmony_ci DD_WRITE = WRITE, 4462306a36Sopenharmony_ci}; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cienum { DD_DIR_COUNT = 2 }; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_cienum dd_prio { 4962306a36Sopenharmony_ci DD_RT_PRIO = 0, 5062306a36Sopenharmony_ci DD_BE_PRIO = 1, 5162306a36Sopenharmony_ci DD_IDLE_PRIO = 2, 5262306a36Sopenharmony_ci DD_PRIO_MAX = 2, 5362306a36Sopenharmony_ci}; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_cienum { DD_PRIO_COUNT = 3 }; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* 5862306a36Sopenharmony_ci * I/O statistics per I/O priority. It is fine if these counters overflow. 5962306a36Sopenharmony_ci * What matters is that these counters are at least as wide as 6062306a36Sopenharmony_ci * log2(max_outstanding_requests). 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_cistruct io_stats_per_prio { 6362306a36Sopenharmony_ci uint32_t inserted; 6462306a36Sopenharmony_ci uint32_t merged; 6562306a36Sopenharmony_ci uint32_t dispatched; 6662306a36Sopenharmony_ci atomic_t completed; 6762306a36Sopenharmony_ci}; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Deadline scheduler data per I/O priority (enum dd_prio). Requests are 7162306a36Sopenharmony_ci * present on both sort_list[] and fifo_list[]. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistruct dd_per_prio { 7462306a36Sopenharmony_ci struct list_head dispatch; 7562306a36Sopenharmony_ci struct rb_root sort_list[DD_DIR_COUNT]; 7662306a36Sopenharmony_ci struct list_head fifo_list[DD_DIR_COUNT]; 7762306a36Sopenharmony_ci /* Position of the most recently dispatched request. */ 7862306a36Sopenharmony_ci sector_t latest_pos[DD_DIR_COUNT]; 7962306a36Sopenharmony_ci struct io_stats_per_prio stats; 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistruct deadline_data { 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * run time data 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci struct dd_per_prio per_prio[DD_PRIO_COUNT]; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* Data direction of latest dispatched request. */ 9062306a36Sopenharmony_ci enum dd_data_dir last_dir; 9162306a36Sopenharmony_ci unsigned int batching; /* number of sequential requests made */ 9262306a36Sopenharmony_ci unsigned int starved; /* times reads have starved writes */ 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci /* 9562306a36Sopenharmony_ci * settings that change how the i/o scheduler behaves 9662306a36Sopenharmony_ci */ 9762306a36Sopenharmony_ci int fifo_expire[DD_DIR_COUNT]; 9862306a36Sopenharmony_ci int fifo_batch; 9962306a36Sopenharmony_ci int writes_starved; 10062306a36Sopenharmony_ci int front_merges; 10162306a36Sopenharmony_ci u32 async_depth; 10262306a36Sopenharmony_ci int prio_aging_expire; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci spinlock_t lock; 10562306a36Sopenharmony_ci spinlock_t zone_lock; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/* Maps an I/O priority class to a deadline scheduler priority. */ 10962306a36Sopenharmony_cistatic const enum dd_prio ioprio_class_to_prio[] = { 11062306a36Sopenharmony_ci [IOPRIO_CLASS_NONE] = DD_BE_PRIO, 11162306a36Sopenharmony_ci [IOPRIO_CLASS_RT] = DD_RT_PRIO, 11262306a36Sopenharmony_ci [IOPRIO_CLASS_BE] = DD_BE_PRIO, 11362306a36Sopenharmony_ci [IOPRIO_CLASS_IDLE] = DD_IDLE_PRIO, 11462306a36Sopenharmony_ci}; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic inline struct rb_root * 11762306a36Sopenharmony_cideadline_rb_root(struct dd_per_prio *per_prio, struct request *rq) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci return &per_prio->sort_list[rq_data_dir(rq)]; 12062306a36Sopenharmony_ci} 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * Returns the I/O priority class (IOPRIO_CLASS_*) that has been assigned to a 12462306a36Sopenharmony_ci * request. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic u8 dd_rq_ioclass(struct request *rq) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci return IOPRIO_PRIO_CLASS(req_get_ioprio(rq)); 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* 13262306a36Sopenharmony_ci * get the request before `rq' in sector-sorted order 13362306a36Sopenharmony_ci */ 13462306a36Sopenharmony_cistatic inline struct request * 13562306a36Sopenharmony_cideadline_earlier_request(struct request *rq) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct rb_node *node = rb_prev(&rq->rb_node); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (node) 14062306a36Sopenharmony_ci return rb_entry_rq(node); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return NULL; 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci/* 14662306a36Sopenharmony_ci * get the request after `rq' in sector-sorted order 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic inline struct request * 14962306a36Sopenharmony_cideadline_latter_request(struct request *rq) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct rb_node *node = rb_next(&rq->rb_node); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (node) 15462306a36Sopenharmony_ci return rb_entry_rq(node); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return NULL; 15762306a36Sopenharmony_ci} 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci/* 16062306a36Sopenharmony_ci * Return the first request for which blk_rq_pos() >= @pos. For zoned devices, 16162306a36Sopenharmony_ci * return the first request after the start of the zone containing @pos. 16262306a36Sopenharmony_ci */ 16362306a36Sopenharmony_cistatic inline struct request *deadline_from_pos(struct dd_per_prio *per_prio, 16462306a36Sopenharmony_ci enum dd_data_dir data_dir, sector_t pos) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct rb_node *node = per_prio->sort_list[data_dir].rb_node; 16762306a36Sopenharmony_ci struct request *rq, *res = NULL; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!node) 17062306a36Sopenharmony_ci return NULL; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci rq = rb_entry_rq(node); 17362306a36Sopenharmony_ci /* 17462306a36Sopenharmony_ci * A zoned write may have been requeued with a starting position that 17562306a36Sopenharmony_ci * is below that of the most recently dispatched request. Hence, for 17662306a36Sopenharmony_ci * zoned writes, start searching from the start of a zone. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ci if (blk_rq_is_seq_zoned_write(rq)) 17962306a36Sopenharmony_ci pos = round_down(pos, rq->q->limits.chunk_sectors); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci while (node) { 18262306a36Sopenharmony_ci rq = rb_entry_rq(node); 18362306a36Sopenharmony_ci if (blk_rq_pos(rq) >= pos) { 18462306a36Sopenharmony_ci res = rq; 18562306a36Sopenharmony_ci node = node->rb_left; 18662306a36Sopenharmony_ci } else { 18762306a36Sopenharmony_ci node = node->rb_right; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci return res; 19162306a36Sopenharmony_ci} 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_cistatic void 19462306a36Sopenharmony_cideadline_add_rq_rb(struct dd_per_prio *per_prio, struct request *rq) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct rb_root *root = deadline_rb_root(per_prio, rq); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci elv_rb_add(root, rq); 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistatic inline void 20262306a36Sopenharmony_cideadline_del_rq_rb(struct dd_per_prio *per_prio, struct request *rq) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci elv_rb_del(deadline_rb_root(per_prio, rq), rq); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci/* 20862306a36Sopenharmony_ci * remove rq from rbtree and fifo. 20962306a36Sopenharmony_ci */ 21062306a36Sopenharmony_cistatic void deadline_remove_request(struct request_queue *q, 21162306a36Sopenharmony_ci struct dd_per_prio *per_prio, 21262306a36Sopenharmony_ci struct request *rq) 21362306a36Sopenharmony_ci{ 21462306a36Sopenharmony_ci list_del_init(&rq->queuelist); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* 21762306a36Sopenharmony_ci * We might not be on the rbtree, if we are doing an insert merge 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci if (!RB_EMPTY_NODE(&rq->rb_node)) 22062306a36Sopenharmony_ci deadline_del_rq_rb(per_prio, rq); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci elv_rqhash_del(q, rq); 22362306a36Sopenharmony_ci if (q->last_merge == rq) 22462306a36Sopenharmony_ci q->last_merge = NULL; 22562306a36Sopenharmony_ci} 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic void dd_request_merged(struct request_queue *q, struct request *req, 22862306a36Sopenharmony_ci enum elv_merge type) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 23162306a36Sopenharmony_ci const u8 ioprio_class = dd_rq_ioclass(req); 23262306a36Sopenharmony_ci const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; 23362306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * if the merge was a front merge, we need to reposition request 23762306a36Sopenharmony_ci */ 23862306a36Sopenharmony_ci if (type == ELEVATOR_FRONT_MERGE) { 23962306a36Sopenharmony_ci elv_rb_del(deadline_rb_root(per_prio, req), req); 24062306a36Sopenharmony_ci deadline_add_rq_rb(per_prio, req); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci/* 24562306a36Sopenharmony_ci * Callback function that is invoked after @next has been merged into @req. 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_cistatic void dd_merged_requests(struct request_queue *q, struct request *req, 24862306a36Sopenharmony_ci struct request *next) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 25162306a36Sopenharmony_ci const u8 ioprio_class = dd_rq_ioclass(next); 25262306a36Sopenharmony_ci const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci dd->per_prio[prio].stats.merged++; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * if next expires before rq, assign its expire time to rq 26062306a36Sopenharmony_ci * and move into next position (next will be deleted) in fifo 26162306a36Sopenharmony_ci */ 26262306a36Sopenharmony_ci if (!list_empty(&req->queuelist) && !list_empty(&next->queuelist)) { 26362306a36Sopenharmony_ci if (time_before((unsigned long)next->fifo_time, 26462306a36Sopenharmony_ci (unsigned long)req->fifo_time)) { 26562306a36Sopenharmony_ci list_move(&req->queuelist, &next->queuelist); 26662306a36Sopenharmony_ci req->fifo_time = next->fifo_time; 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci } 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci /* 27162306a36Sopenharmony_ci * kill knowledge of next, this one is a goner 27262306a36Sopenharmony_ci */ 27362306a36Sopenharmony_ci deadline_remove_request(q, &dd->per_prio[prio], next); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci/* 27762306a36Sopenharmony_ci * move an entry to dispatch queue 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic void 28062306a36Sopenharmony_cideadline_move_request(struct deadline_data *dd, struct dd_per_prio *per_prio, 28162306a36Sopenharmony_ci struct request *rq) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci /* 28462306a36Sopenharmony_ci * take it off the sort and fifo list 28562306a36Sopenharmony_ci */ 28662306a36Sopenharmony_ci deadline_remove_request(rq->q, per_prio, rq); 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci/* Number of requests queued for a given priority level. */ 29062306a36Sopenharmony_cistatic u32 dd_queued(struct deadline_data *dd, enum dd_prio prio) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci const struct io_stats_per_prio *stats = &dd->per_prio[prio].stats; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci return stats->inserted - atomic_read(&stats->completed); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci/* 30062306a36Sopenharmony_ci * deadline_check_fifo returns true if and only if there are expired requests 30162306a36Sopenharmony_ci * in the FIFO list. Requires !list_empty(&dd->fifo_list[data_dir]). 30262306a36Sopenharmony_ci */ 30362306a36Sopenharmony_cistatic inline bool deadline_check_fifo(struct dd_per_prio *per_prio, 30462306a36Sopenharmony_ci enum dd_data_dir data_dir) 30562306a36Sopenharmony_ci{ 30662306a36Sopenharmony_ci struct request *rq = rq_entry_fifo(per_prio->fifo_list[data_dir].next); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return time_is_before_eq_jiffies((unsigned long)rq->fifo_time); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci/* 31262306a36Sopenharmony_ci * Check if rq has a sequential request preceding it. 31362306a36Sopenharmony_ci */ 31462306a36Sopenharmony_cistatic bool deadline_is_seq_write(struct deadline_data *dd, struct request *rq) 31562306a36Sopenharmony_ci{ 31662306a36Sopenharmony_ci struct request *prev = deadline_earlier_request(rq); 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!prev) 31962306a36Sopenharmony_ci return false; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci return blk_rq_pos(prev) + blk_rq_sectors(prev) == blk_rq_pos(rq); 32262306a36Sopenharmony_ci} 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci/* 32562306a36Sopenharmony_ci * Skip all write requests that are sequential from @rq, even if we cross 32662306a36Sopenharmony_ci * a zone boundary. 32762306a36Sopenharmony_ci */ 32862306a36Sopenharmony_cistatic struct request *deadline_skip_seq_writes(struct deadline_data *dd, 32962306a36Sopenharmony_ci struct request *rq) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci sector_t pos = blk_rq_pos(rq); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci do { 33462306a36Sopenharmony_ci pos += blk_rq_sectors(rq); 33562306a36Sopenharmony_ci rq = deadline_latter_request(rq); 33662306a36Sopenharmony_ci } while (rq && blk_rq_pos(rq) == pos); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci return rq; 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * For the specified data direction, return the next request to 34362306a36Sopenharmony_ci * dispatch using arrival ordered lists. 34462306a36Sopenharmony_ci */ 34562306a36Sopenharmony_cistatic struct request * 34662306a36Sopenharmony_cideadline_fifo_request(struct deadline_data *dd, struct dd_per_prio *per_prio, 34762306a36Sopenharmony_ci enum dd_data_dir data_dir) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct request *rq, *rb_rq, *next; 35062306a36Sopenharmony_ci unsigned long flags; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (list_empty(&per_prio->fifo_list[data_dir])) 35362306a36Sopenharmony_ci return NULL; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci rq = rq_entry_fifo(per_prio->fifo_list[data_dir].next); 35662306a36Sopenharmony_ci if (data_dir == DD_READ || !blk_queue_is_zoned(rq->q)) 35762306a36Sopenharmony_ci return rq; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci /* 36062306a36Sopenharmony_ci * Look for a write request that can be dispatched, that is one with 36162306a36Sopenharmony_ci * an unlocked target zone. For some HDDs, breaking a sequential 36262306a36Sopenharmony_ci * write stream can lead to lower throughput, so make sure to preserve 36362306a36Sopenharmony_ci * sequential write streams, even if that stream crosses into the next 36462306a36Sopenharmony_ci * zones and these zones are unlocked. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci spin_lock_irqsave(&dd->zone_lock, flags); 36762306a36Sopenharmony_ci list_for_each_entry_safe(rq, next, &per_prio->fifo_list[DD_WRITE], 36862306a36Sopenharmony_ci queuelist) { 36962306a36Sopenharmony_ci /* Check whether a prior request exists for the same zone. */ 37062306a36Sopenharmony_ci rb_rq = deadline_from_pos(per_prio, data_dir, blk_rq_pos(rq)); 37162306a36Sopenharmony_ci if (rb_rq && blk_rq_pos(rb_rq) < blk_rq_pos(rq)) 37262306a36Sopenharmony_ci rq = rb_rq; 37362306a36Sopenharmony_ci if (blk_req_can_dispatch_to_zone(rq) && 37462306a36Sopenharmony_ci (blk_queue_nonrot(rq->q) || 37562306a36Sopenharmony_ci !deadline_is_seq_write(dd, rq))) 37662306a36Sopenharmony_ci goto out; 37762306a36Sopenharmony_ci } 37862306a36Sopenharmony_ci rq = NULL; 37962306a36Sopenharmony_ciout: 38062306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->zone_lock, flags); 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci return rq; 38362306a36Sopenharmony_ci} 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci/* 38662306a36Sopenharmony_ci * For the specified data direction, return the next request to 38762306a36Sopenharmony_ci * dispatch using sector position sorted lists. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_cistatic struct request * 39062306a36Sopenharmony_cideadline_next_request(struct deadline_data *dd, struct dd_per_prio *per_prio, 39162306a36Sopenharmony_ci enum dd_data_dir data_dir) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci struct request *rq; 39462306a36Sopenharmony_ci unsigned long flags; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci rq = deadline_from_pos(per_prio, data_dir, 39762306a36Sopenharmony_ci per_prio->latest_pos[data_dir]); 39862306a36Sopenharmony_ci if (!rq) 39962306a36Sopenharmony_ci return NULL; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci if (data_dir == DD_READ || !blk_queue_is_zoned(rq->q)) 40262306a36Sopenharmony_ci return rq; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* 40562306a36Sopenharmony_ci * Look for a write request that can be dispatched, that is one with 40662306a36Sopenharmony_ci * an unlocked target zone. For some HDDs, breaking a sequential 40762306a36Sopenharmony_ci * write stream can lead to lower throughput, so make sure to preserve 40862306a36Sopenharmony_ci * sequential write streams, even if that stream crosses into the next 40962306a36Sopenharmony_ci * zones and these zones are unlocked. 41062306a36Sopenharmony_ci */ 41162306a36Sopenharmony_ci spin_lock_irqsave(&dd->zone_lock, flags); 41262306a36Sopenharmony_ci while (rq) { 41362306a36Sopenharmony_ci if (blk_req_can_dispatch_to_zone(rq)) 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci if (blk_queue_nonrot(rq->q)) 41662306a36Sopenharmony_ci rq = deadline_latter_request(rq); 41762306a36Sopenharmony_ci else 41862306a36Sopenharmony_ci rq = deadline_skip_seq_writes(dd, rq); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->zone_lock, flags); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci return rq; 42362306a36Sopenharmony_ci} 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci/* 42662306a36Sopenharmony_ci * Returns true if and only if @rq started after @latest_start where 42762306a36Sopenharmony_ci * @latest_start is in jiffies. 42862306a36Sopenharmony_ci */ 42962306a36Sopenharmony_cistatic bool started_after(struct deadline_data *dd, struct request *rq, 43062306a36Sopenharmony_ci unsigned long latest_start) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci unsigned long start_time = (unsigned long)rq->fifo_time; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci start_time -= dd->fifo_expire[rq_data_dir(rq)]; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return time_after(start_time, latest_start); 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * deadline_dispatch_requests selects the best request according to 44162306a36Sopenharmony_ci * read/write expire, fifo_batch, etc and with a start time <= @latest_start. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic struct request *__dd_dispatch_request(struct deadline_data *dd, 44462306a36Sopenharmony_ci struct dd_per_prio *per_prio, 44562306a36Sopenharmony_ci unsigned long latest_start) 44662306a36Sopenharmony_ci{ 44762306a36Sopenharmony_ci struct request *rq, *next_rq; 44862306a36Sopenharmony_ci enum dd_data_dir data_dir; 44962306a36Sopenharmony_ci enum dd_prio prio; 45062306a36Sopenharmony_ci u8 ioprio_class; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci if (!list_empty(&per_prio->dispatch)) { 45562306a36Sopenharmony_ci rq = list_first_entry(&per_prio->dispatch, struct request, 45662306a36Sopenharmony_ci queuelist); 45762306a36Sopenharmony_ci if (started_after(dd, rq, latest_start)) 45862306a36Sopenharmony_ci return NULL; 45962306a36Sopenharmony_ci list_del_init(&rq->queuelist); 46062306a36Sopenharmony_ci data_dir = rq_data_dir(rq); 46162306a36Sopenharmony_ci goto done; 46262306a36Sopenharmony_ci } 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * batches are currently reads XOR writes 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ci rq = deadline_next_request(dd, per_prio, dd->last_dir); 46862306a36Sopenharmony_ci if (rq && dd->batching < dd->fifo_batch) { 46962306a36Sopenharmony_ci /* we have a next request and are still entitled to batch */ 47062306a36Sopenharmony_ci data_dir = rq_data_dir(rq); 47162306a36Sopenharmony_ci goto dispatch_request; 47262306a36Sopenharmony_ci } 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * at this point we are not running a batch. select the appropriate 47662306a36Sopenharmony_ci * data direction (read / write) 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_ci if (!list_empty(&per_prio->fifo_list[DD_READ])) { 48062306a36Sopenharmony_ci BUG_ON(RB_EMPTY_ROOT(&per_prio->sort_list[DD_READ])); 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (deadline_fifo_request(dd, per_prio, DD_WRITE) && 48362306a36Sopenharmony_ci (dd->starved++ >= dd->writes_starved)) 48462306a36Sopenharmony_ci goto dispatch_writes; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci data_dir = DD_READ; 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci goto dispatch_find_request; 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci /* 49262306a36Sopenharmony_ci * there are either no reads or writes have been starved 49362306a36Sopenharmony_ci */ 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci if (!list_empty(&per_prio->fifo_list[DD_WRITE])) { 49662306a36Sopenharmony_cidispatch_writes: 49762306a36Sopenharmony_ci BUG_ON(RB_EMPTY_ROOT(&per_prio->sort_list[DD_WRITE])); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci dd->starved = 0; 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci data_dir = DD_WRITE; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci goto dispatch_find_request; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci return NULL; 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_cidispatch_find_request: 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * we are not running a batch, find best request for selected data_dir 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci next_rq = deadline_next_request(dd, per_prio, data_dir); 51362306a36Sopenharmony_ci if (deadline_check_fifo(per_prio, data_dir) || !next_rq) { 51462306a36Sopenharmony_ci /* 51562306a36Sopenharmony_ci * A deadline has expired, the last request was in the other 51662306a36Sopenharmony_ci * direction, or we have run out of higher-sectored requests. 51762306a36Sopenharmony_ci * Start again from the request with the earliest expiry time. 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci rq = deadline_fifo_request(dd, per_prio, data_dir); 52062306a36Sopenharmony_ci } else { 52162306a36Sopenharmony_ci /* 52262306a36Sopenharmony_ci * The last req was the same dir and we have a next request in 52362306a36Sopenharmony_ci * sort order. No expired requests so continue on from here. 52462306a36Sopenharmony_ci */ 52562306a36Sopenharmony_ci rq = next_rq; 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci /* 52962306a36Sopenharmony_ci * For a zoned block device, if we only have writes queued and none of 53062306a36Sopenharmony_ci * them can be dispatched, rq will be NULL. 53162306a36Sopenharmony_ci */ 53262306a36Sopenharmony_ci if (!rq) 53362306a36Sopenharmony_ci return NULL; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci dd->last_dir = data_dir; 53662306a36Sopenharmony_ci dd->batching = 0; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_cidispatch_request: 53962306a36Sopenharmony_ci if (started_after(dd, rq, latest_start)) 54062306a36Sopenharmony_ci return NULL; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci /* 54362306a36Sopenharmony_ci * rq is the selected appropriate request. 54462306a36Sopenharmony_ci */ 54562306a36Sopenharmony_ci dd->batching++; 54662306a36Sopenharmony_ci deadline_move_request(dd, per_prio, rq); 54762306a36Sopenharmony_cidone: 54862306a36Sopenharmony_ci ioprio_class = dd_rq_ioclass(rq); 54962306a36Sopenharmony_ci prio = ioprio_class_to_prio[ioprio_class]; 55062306a36Sopenharmony_ci dd->per_prio[prio].latest_pos[data_dir] = blk_rq_pos(rq); 55162306a36Sopenharmony_ci dd->per_prio[prio].stats.dispatched++; 55262306a36Sopenharmony_ci /* 55362306a36Sopenharmony_ci * If the request needs its target zone locked, do it. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci blk_req_zone_write_lock(rq); 55662306a36Sopenharmony_ci rq->rq_flags |= RQF_STARTED; 55762306a36Sopenharmony_ci return rq; 55862306a36Sopenharmony_ci} 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci/* 56162306a36Sopenharmony_ci * Check whether there are any requests with priority other than DD_RT_PRIO 56262306a36Sopenharmony_ci * that were inserted more than prio_aging_expire jiffies ago. 56362306a36Sopenharmony_ci */ 56462306a36Sopenharmony_cistatic struct request *dd_dispatch_prio_aged_requests(struct deadline_data *dd, 56562306a36Sopenharmony_ci unsigned long now) 56662306a36Sopenharmony_ci{ 56762306a36Sopenharmony_ci struct request *rq; 56862306a36Sopenharmony_ci enum dd_prio prio; 56962306a36Sopenharmony_ci int prio_cnt; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci prio_cnt = !!dd_queued(dd, DD_RT_PRIO) + !!dd_queued(dd, DD_BE_PRIO) + 57462306a36Sopenharmony_ci !!dd_queued(dd, DD_IDLE_PRIO); 57562306a36Sopenharmony_ci if (prio_cnt < 2) 57662306a36Sopenharmony_ci return NULL; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci for (prio = DD_BE_PRIO; prio <= DD_PRIO_MAX; prio++) { 57962306a36Sopenharmony_ci rq = __dd_dispatch_request(dd, &dd->per_prio[prio], 58062306a36Sopenharmony_ci now - dd->prio_aging_expire); 58162306a36Sopenharmony_ci if (rq) 58262306a36Sopenharmony_ci return rq; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci return NULL; 58662306a36Sopenharmony_ci} 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci/* 58962306a36Sopenharmony_ci * Called from blk_mq_run_hw_queue() -> __blk_mq_sched_dispatch_requests(). 59062306a36Sopenharmony_ci * 59162306a36Sopenharmony_ci * One confusing aspect here is that we get called for a specific 59262306a36Sopenharmony_ci * hardware queue, but we may return a request that is for a 59362306a36Sopenharmony_ci * different hardware queue. This is because mq-deadline has shared 59462306a36Sopenharmony_ci * state for all hardware queues, in terms of sorting, FIFOs, etc. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_cistatic struct request *dd_dispatch_request(struct blk_mq_hw_ctx *hctx) 59762306a36Sopenharmony_ci{ 59862306a36Sopenharmony_ci struct deadline_data *dd = hctx->queue->elevator->elevator_data; 59962306a36Sopenharmony_ci const unsigned long now = jiffies; 60062306a36Sopenharmony_ci struct request *rq; 60162306a36Sopenharmony_ci enum dd_prio prio; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci spin_lock(&dd->lock); 60462306a36Sopenharmony_ci rq = dd_dispatch_prio_aged_requests(dd, now); 60562306a36Sopenharmony_ci if (rq) 60662306a36Sopenharmony_ci goto unlock; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* 60962306a36Sopenharmony_ci * Next, dispatch requests in priority order. Ignore lower priority 61062306a36Sopenharmony_ci * requests if any higher priority requests are pending. 61162306a36Sopenharmony_ci */ 61262306a36Sopenharmony_ci for (prio = 0; prio <= DD_PRIO_MAX; prio++) { 61362306a36Sopenharmony_ci rq = __dd_dispatch_request(dd, &dd->per_prio[prio], now); 61462306a36Sopenharmony_ci if (rq || dd_queued(dd, prio)) 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci } 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ciunlock: 61962306a36Sopenharmony_ci spin_unlock(&dd->lock); 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci return rq; 62262306a36Sopenharmony_ci} 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci/* 62562306a36Sopenharmony_ci * Called by __blk_mq_alloc_request(). The shallow_depth value set by this 62662306a36Sopenharmony_ci * function is used by __blk_mq_get_tag(). 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_cistatic void dd_limit_depth(blk_opf_t opf, struct blk_mq_alloc_data *data) 62962306a36Sopenharmony_ci{ 63062306a36Sopenharmony_ci struct deadline_data *dd = data->q->elevator->elevator_data; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Do not throttle synchronous reads. */ 63362306a36Sopenharmony_ci if (op_is_sync(opf) && !op_is_write(opf)) 63462306a36Sopenharmony_ci return; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci /* 63762306a36Sopenharmony_ci * Throttle asynchronous requests and writes such that these requests 63862306a36Sopenharmony_ci * do not block the allocation of synchronous requests. 63962306a36Sopenharmony_ci */ 64062306a36Sopenharmony_ci data->shallow_depth = dd->async_depth; 64162306a36Sopenharmony_ci} 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci/* Called by blk_mq_update_nr_requests(). */ 64462306a36Sopenharmony_cistatic void dd_depth_updated(struct blk_mq_hw_ctx *hctx) 64562306a36Sopenharmony_ci{ 64662306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 64762306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 64862306a36Sopenharmony_ci struct blk_mq_tags *tags = hctx->sched_tags; 64962306a36Sopenharmony_ci unsigned int shift = tags->bitmap_tags.sb.shift; 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci dd->async_depth = max(1U, 3 * (1U << shift) / 4); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci sbitmap_queue_min_shallow_depth(&tags->bitmap_tags, dd->async_depth); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci/* Called by blk_mq_init_hctx() and blk_mq_init_sched(). */ 65762306a36Sopenharmony_cistatic int dd_init_hctx(struct blk_mq_hw_ctx *hctx, unsigned int hctx_idx) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci dd_depth_updated(hctx); 66062306a36Sopenharmony_ci return 0; 66162306a36Sopenharmony_ci} 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_cistatic void dd_exit_sched(struct elevator_queue *e) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct deadline_data *dd = e->elevator_data; 66662306a36Sopenharmony_ci enum dd_prio prio; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (prio = 0; prio <= DD_PRIO_MAX; prio++) { 66962306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; 67062306a36Sopenharmony_ci const struct io_stats_per_prio *stats = &per_prio->stats; 67162306a36Sopenharmony_ci uint32_t queued; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&per_prio->fifo_list[DD_READ])); 67462306a36Sopenharmony_ci WARN_ON_ONCE(!list_empty(&per_prio->fifo_list[DD_WRITE])); 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci spin_lock(&dd->lock); 67762306a36Sopenharmony_ci queued = dd_queued(dd, prio); 67862306a36Sopenharmony_ci spin_unlock(&dd->lock); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci WARN_ONCE(queued != 0, 68162306a36Sopenharmony_ci "statistics for priority %d: i %u m %u d %u c %u\n", 68262306a36Sopenharmony_ci prio, stats->inserted, stats->merged, 68362306a36Sopenharmony_ci stats->dispatched, atomic_read(&stats->completed)); 68462306a36Sopenharmony_ci } 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci kfree(dd); 68762306a36Sopenharmony_ci} 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci/* 69062306a36Sopenharmony_ci * initialize elevator private data (deadline_data). 69162306a36Sopenharmony_ci */ 69262306a36Sopenharmony_cistatic int dd_init_sched(struct request_queue *q, struct elevator_type *e) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct deadline_data *dd; 69562306a36Sopenharmony_ci struct elevator_queue *eq; 69662306a36Sopenharmony_ci enum dd_prio prio; 69762306a36Sopenharmony_ci int ret = -ENOMEM; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci eq = elevator_alloc(q, e); 70062306a36Sopenharmony_ci if (!eq) 70162306a36Sopenharmony_ci return ret; 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci dd = kzalloc_node(sizeof(*dd), GFP_KERNEL, q->node); 70462306a36Sopenharmony_ci if (!dd) 70562306a36Sopenharmony_ci goto put_eq; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci eq->elevator_data = dd; 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci for (prio = 0; prio <= DD_PRIO_MAX; prio++) { 71062306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci INIT_LIST_HEAD(&per_prio->dispatch); 71362306a36Sopenharmony_ci INIT_LIST_HEAD(&per_prio->fifo_list[DD_READ]); 71462306a36Sopenharmony_ci INIT_LIST_HEAD(&per_prio->fifo_list[DD_WRITE]); 71562306a36Sopenharmony_ci per_prio->sort_list[DD_READ] = RB_ROOT; 71662306a36Sopenharmony_ci per_prio->sort_list[DD_WRITE] = RB_ROOT; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci dd->fifo_expire[DD_READ] = read_expire; 71962306a36Sopenharmony_ci dd->fifo_expire[DD_WRITE] = write_expire; 72062306a36Sopenharmony_ci dd->writes_starved = writes_starved; 72162306a36Sopenharmony_ci dd->front_merges = 1; 72262306a36Sopenharmony_ci dd->last_dir = DD_WRITE; 72362306a36Sopenharmony_ci dd->fifo_batch = fifo_batch; 72462306a36Sopenharmony_ci dd->prio_aging_expire = prio_aging_expire; 72562306a36Sopenharmony_ci spin_lock_init(&dd->lock); 72662306a36Sopenharmony_ci spin_lock_init(&dd->zone_lock); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* We dispatch from request queue wide instead of hw queue */ 72962306a36Sopenharmony_ci blk_queue_flag_set(QUEUE_FLAG_SQ_SCHED, q); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci q->elevator = eq; 73262306a36Sopenharmony_ci return 0; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ciput_eq: 73562306a36Sopenharmony_ci kobject_put(&eq->kobj); 73662306a36Sopenharmony_ci return ret; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci/* 74062306a36Sopenharmony_ci * Try to merge @bio into an existing request. If @bio has been merged into 74162306a36Sopenharmony_ci * an existing request, store the pointer to that request into *@rq. 74262306a36Sopenharmony_ci */ 74362306a36Sopenharmony_cistatic int dd_request_merge(struct request_queue *q, struct request **rq, 74462306a36Sopenharmony_ci struct bio *bio) 74562306a36Sopenharmony_ci{ 74662306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 74762306a36Sopenharmony_ci const u8 ioprio_class = IOPRIO_PRIO_CLASS(bio->bi_ioprio); 74862306a36Sopenharmony_ci const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; 74962306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; 75062306a36Sopenharmony_ci sector_t sector = bio_end_sector(bio); 75162306a36Sopenharmony_ci struct request *__rq; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci if (!dd->front_merges) 75462306a36Sopenharmony_ci return ELEVATOR_NO_MERGE; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci __rq = elv_rb_find(&per_prio->sort_list[bio_data_dir(bio)], sector); 75762306a36Sopenharmony_ci if (__rq) { 75862306a36Sopenharmony_ci BUG_ON(sector != blk_rq_pos(__rq)); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci if (elv_bio_merge_ok(__rq, bio)) { 76162306a36Sopenharmony_ci *rq = __rq; 76262306a36Sopenharmony_ci if (blk_discard_mergable(__rq)) 76362306a36Sopenharmony_ci return ELEVATOR_DISCARD_MERGE; 76462306a36Sopenharmony_ci return ELEVATOR_FRONT_MERGE; 76562306a36Sopenharmony_ci } 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return ELEVATOR_NO_MERGE; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/* 77262306a36Sopenharmony_ci * Attempt to merge a bio into an existing request. This function is called 77362306a36Sopenharmony_ci * before @bio is associated with a request. 77462306a36Sopenharmony_ci */ 77562306a36Sopenharmony_cistatic bool dd_bio_merge(struct request_queue *q, struct bio *bio, 77662306a36Sopenharmony_ci unsigned int nr_segs) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 77962306a36Sopenharmony_ci struct request *free = NULL; 78062306a36Sopenharmony_ci bool ret; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci spin_lock(&dd->lock); 78362306a36Sopenharmony_ci ret = blk_mq_sched_try_merge(q, bio, nr_segs, &free); 78462306a36Sopenharmony_ci spin_unlock(&dd->lock); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci if (free) 78762306a36Sopenharmony_ci blk_mq_free_request(free); 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return ret; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci/* 79362306a36Sopenharmony_ci * add rq to rbtree and fifo 79462306a36Sopenharmony_ci */ 79562306a36Sopenharmony_cistatic void dd_insert_request(struct blk_mq_hw_ctx *hctx, struct request *rq, 79662306a36Sopenharmony_ci blk_insert_t flags, struct list_head *free) 79762306a36Sopenharmony_ci{ 79862306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 79962306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 80062306a36Sopenharmony_ci const enum dd_data_dir data_dir = rq_data_dir(rq); 80162306a36Sopenharmony_ci u16 ioprio = req_get_ioprio(rq); 80262306a36Sopenharmony_ci u8 ioprio_class = IOPRIO_PRIO_CLASS(ioprio); 80362306a36Sopenharmony_ci struct dd_per_prio *per_prio; 80462306a36Sopenharmony_ci enum dd_prio prio; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * This may be a requeue of a write request that has locked its 81062306a36Sopenharmony_ci * target zone. If it is the case, this releases the zone lock. 81162306a36Sopenharmony_ci */ 81262306a36Sopenharmony_ci blk_req_zone_write_unlock(rq); 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci prio = ioprio_class_to_prio[ioprio_class]; 81562306a36Sopenharmony_ci per_prio = &dd->per_prio[prio]; 81662306a36Sopenharmony_ci if (!rq->elv.priv[0]) { 81762306a36Sopenharmony_ci per_prio->stats.inserted++; 81862306a36Sopenharmony_ci rq->elv.priv[0] = (void *)(uintptr_t)1; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (blk_mq_sched_try_insert_merge(q, rq, free)) 82262306a36Sopenharmony_ci return; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci trace_block_rq_insert(rq); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci if (flags & BLK_MQ_INSERT_AT_HEAD) { 82762306a36Sopenharmony_ci list_add(&rq->queuelist, &per_prio->dispatch); 82862306a36Sopenharmony_ci rq->fifo_time = jiffies; 82962306a36Sopenharmony_ci } else { 83062306a36Sopenharmony_ci struct list_head *insert_before; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci deadline_add_rq_rb(per_prio, rq); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (rq_mergeable(rq)) { 83562306a36Sopenharmony_ci elv_rqhash_add(q, rq); 83662306a36Sopenharmony_ci if (!q->last_merge) 83762306a36Sopenharmony_ci q->last_merge = rq; 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* 84162306a36Sopenharmony_ci * set expire time and add to fifo list 84262306a36Sopenharmony_ci */ 84362306a36Sopenharmony_ci rq->fifo_time = jiffies + dd->fifo_expire[data_dir]; 84462306a36Sopenharmony_ci insert_before = &per_prio->fifo_list[data_dir]; 84562306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEV_ZONED 84662306a36Sopenharmony_ci /* 84762306a36Sopenharmony_ci * Insert zoned writes such that requests are sorted by 84862306a36Sopenharmony_ci * position per zone. 84962306a36Sopenharmony_ci */ 85062306a36Sopenharmony_ci if (blk_rq_is_seq_zoned_write(rq)) { 85162306a36Sopenharmony_ci struct request *rq2 = deadline_latter_request(rq); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (rq2 && blk_rq_zone_no(rq2) == blk_rq_zone_no(rq)) 85462306a36Sopenharmony_ci insert_before = &rq2->queuelist; 85562306a36Sopenharmony_ci } 85662306a36Sopenharmony_ci#endif 85762306a36Sopenharmony_ci list_add_tail(&rq->queuelist, insert_before); 85862306a36Sopenharmony_ci } 85962306a36Sopenharmony_ci} 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci/* 86262306a36Sopenharmony_ci * Called from blk_mq_insert_request() or blk_mq_dispatch_plug_list(). 86362306a36Sopenharmony_ci */ 86462306a36Sopenharmony_cistatic void dd_insert_requests(struct blk_mq_hw_ctx *hctx, 86562306a36Sopenharmony_ci struct list_head *list, 86662306a36Sopenharmony_ci blk_insert_t flags) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct request_queue *q = hctx->queue; 86962306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 87062306a36Sopenharmony_ci LIST_HEAD(free); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci spin_lock(&dd->lock); 87362306a36Sopenharmony_ci while (!list_empty(list)) { 87462306a36Sopenharmony_ci struct request *rq; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci rq = list_first_entry(list, struct request, queuelist); 87762306a36Sopenharmony_ci list_del_init(&rq->queuelist); 87862306a36Sopenharmony_ci dd_insert_request(hctx, rq, flags, &free); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci spin_unlock(&dd->lock); 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci blk_mq_free_requests(&free); 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* Callback from inside blk_mq_rq_ctx_init(). */ 88662306a36Sopenharmony_cistatic void dd_prepare_request(struct request *rq) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci rq->elv.priv[0] = NULL; 88962306a36Sopenharmony_ci} 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_cistatic bool dd_has_write_work(struct blk_mq_hw_ctx *hctx) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci struct deadline_data *dd = hctx->queue->elevator->elevator_data; 89462306a36Sopenharmony_ci enum dd_prio p; 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci for (p = 0; p <= DD_PRIO_MAX; p++) 89762306a36Sopenharmony_ci if (!list_empty_careful(&dd->per_prio[p].fifo_list[DD_WRITE])) 89862306a36Sopenharmony_ci return true; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci return false; 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci/* 90462306a36Sopenharmony_ci * Callback from inside blk_mq_free_request(). 90562306a36Sopenharmony_ci * 90662306a36Sopenharmony_ci * For zoned block devices, write unlock the target zone of 90762306a36Sopenharmony_ci * completed write requests. Do this while holding the zone lock 90862306a36Sopenharmony_ci * spinlock so that the zone is never unlocked while deadline_fifo_request() 90962306a36Sopenharmony_ci * or deadline_next_request() are executing. This function is called for 91062306a36Sopenharmony_ci * all requests, whether or not these requests complete successfully. 91162306a36Sopenharmony_ci * 91262306a36Sopenharmony_ci * For a zoned block device, __dd_dispatch_request() may have stopped 91362306a36Sopenharmony_ci * dispatching requests if all the queued requests are write requests directed 91462306a36Sopenharmony_ci * at zones that are already locked due to on-going write requests. To ensure 91562306a36Sopenharmony_ci * write request dispatch progress in this case, mark the queue as needing a 91662306a36Sopenharmony_ci * restart to ensure that the queue is run again after completion of the 91762306a36Sopenharmony_ci * request and zones being unlocked. 91862306a36Sopenharmony_ci */ 91962306a36Sopenharmony_cistatic void dd_finish_request(struct request *rq) 92062306a36Sopenharmony_ci{ 92162306a36Sopenharmony_ci struct request_queue *q = rq->q; 92262306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 92362306a36Sopenharmony_ci const u8 ioprio_class = dd_rq_ioclass(rq); 92462306a36Sopenharmony_ci const enum dd_prio prio = ioprio_class_to_prio[ioprio_class]; 92562306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* 92862306a36Sopenharmony_ci * The block layer core may call dd_finish_request() without having 92962306a36Sopenharmony_ci * called dd_insert_requests(). Skip requests that bypassed I/O 93062306a36Sopenharmony_ci * scheduling. See also blk_mq_request_bypass_insert(). 93162306a36Sopenharmony_ci */ 93262306a36Sopenharmony_ci if (!rq->elv.priv[0]) 93362306a36Sopenharmony_ci return; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci atomic_inc(&per_prio->stats.completed); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci if (blk_queue_is_zoned(q)) { 93862306a36Sopenharmony_ci unsigned long flags; 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci spin_lock_irqsave(&dd->zone_lock, flags); 94162306a36Sopenharmony_ci blk_req_zone_write_unlock(rq); 94262306a36Sopenharmony_ci spin_unlock_irqrestore(&dd->zone_lock, flags); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (dd_has_write_work(rq->mq_hctx)) 94562306a36Sopenharmony_ci blk_mq_sched_mark_restart_hctx(rq->mq_hctx); 94662306a36Sopenharmony_ci } 94762306a36Sopenharmony_ci} 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic bool dd_has_work_for_prio(struct dd_per_prio *per_prio) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci return !list_empty_careful(&per_prio->dispatch) || 95262306a36Sopenharmony_ci !list_empty_careful(&per_prio->fifo_list[DD_READ]) || 95362306a36Sopenharmony_ci !list_empty_careful(&per_prio->fifo_list[DD_WRITE]); 95462306a36Sopenharmony_ci} 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_cistatic bool dd_has_work(struct blk_mq_hw_ctx *hctx) 95762306a36Sopenharmony_ci{ 95862306a36Sopenharmony_ci struct deadline_data *dd = hctx->queue->elevator->elevator_data; 95962306a36Sopenharmony_ci enum dd_prio prio; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci for (prio = 0; prio <= DD_PRIO_MAX; prio++) 96262306a36Sopenharmony_ci if (dd_has_work_for_prio(&dd->per_prio[prio])) 96362306a36Sopenharmony_ci return true; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci return false; 96662306a36Sopenharmony_ci} 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci/* 96962306a36Sopenharmony_ci * sysfs parts below 97062306a36Sopenharmony_ci */ 97162306a36Sopenharmony_ci#define SHOW_INT(__FUNC, __VAR) \ 97262306a36Sopenharmony_cistatic ssize_t __FUNC(struct elevator_queue *e, char *page) \ 97362306a36Sopenharmony_ci{ \ 97462306a36Sopenharmony_ci struct deadline_data *dd = e->elevator_data; \ 97562306a36Sopenharmony_ci \ 97662306a36Sopenharmony_ci return sysfs_emit(page, "%d\n", __VAR); \ 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci#define SHOW_JIFFIES(__FUNC, __VAR) SHOW_INT(__FUNC, jiffies_to_msecs(__VAR)) 97962306a36Sopenharmony_ciSHOW_JIFFIES(deadline_read_expire_show, dd->fifo_expire[DD_READ]); 98062306a36Sopenharmony_ciSHOW_JIFFIES(deadline_write_expire_show, dd->fifo_expire[DD_WRITE]); 98162306a36Sopenharmony_ciSHOW_JIFFIES(deadline_prio_aging_expire_show, dd->prio_aging_expire); 98262306a36Sopenharmony_ciSHOW_INT(deadline_writes_starved_show, dd->writes_starved); 98362306a36Sopenharmony_ciSHOW_INT(deadline_front_merges_show, dd->front_merges); 98462306a36Sopenharmony_ciSHOW_INT(deadline_async_depth_show, dd->async_depth); 98562306a36Sopenharmony_ciSHOW_INT(deadline_fifo_batch_show, dd->fifo_batch); 98662306a36Sopenharmony_ci#undef SHOW_INT 98762306a36Sopenharmony_ci#undef SHOW_JIFFIES 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci#define STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, __CONV) \ 99062306a36Sopenharmony_cistatic ssize_t __FUNC(struct elevator_queue *e, const char *page, size_t count) \ 99162306a36Sopenharmony_ci{ \ 99262306a36Sopenharmony_ci struct deadline_data *dd = e->elevator_data; \ 99362306a36Sopenharmony_ci int __data, __ret; \ 99462306a36Sopenharmony_ci \ 99562306a36Sopenharmony_ci __ret = kstrtoint(page, 0, &__data); \ 99662306a36Sopenharmony_ci if (__ret < 0) \ 99762306a36Sopenharmony_ci return __ret; \ 99862306a36Sopenharmony_ci if (__data < (MIN)) \ 99962306a36Sopenharmony_ci __data = (MIN); \ 100062306a36Sopenharmony_ci else if (__data > (MAX)) \ 100162306a36Sopenharmony_ci __data = (MAX); \ 100262306a36Sopenharmony_ci *(__PTR) = __CONV(__data); \ 100362306a36Sopenharmony_ci return count; \ 100462306a36Sopenharmony_ci} 100562306a36Sopenharmony_ci#define STORE_INT(__FUNC, __PTR, MIN, MAX) \ 100662306a36Sopenharmony_ci STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, ) 100762306a36Sopenharmony_ci#define STORE_JIFFIES(__FUNC, __PTR, MIN, MAX) \ 100862306a36Sopenharmony_ci STORE_FUNCTION(__FUNC, __PTR, MIN, MAX, msecs_to_jiffies) 100962306a36Sopenharmony_ciSTORE_JIFFIES(deadline_read_expire_store, &dd->fifo_expire[DD_READ], 0, INT_MAX); 101062306a36Sopenharmony_ciSTORE_JIFFIES(deadline_write_expire_store, &dd->fifo_expire[DD_WRITE], 0, INT_MAX); 101162306a36Sopenharmony_ciSTORE_JIFFIES(deadline_prio_aging_expire_store, &dd->prio_aging_expire, 0, INT_MAX); 101262306a36Sopenharmony_ciSTORE_INT(deadline_writes_starved_store, &dd->writes_starved, INT_MIN, INT_MAX); 101362306a36Sopenharmony_ciSTORE_INT(deadline_front_merges_store, &dd->front_merges, 0, 1); 101462306a36Sopenharmony_ciSTORE_INT(deadline_async_depth_store, &dd->async_depth, 1, INT_MAX); 101562306a36Sopenharmony_ciSTORE_INT(deadline_fifo_batch_store, &dd->fifo_batch, 0, INT_MAX); 101662306a36Sopenharmony_ci#undef STORE_FUNCTION 101762306a36Sopenharmony_ci#undef STORE_INT 101862306a36Sopenharmony_ci#undef STORE_JIFFIES 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci#define DD_ATTR(name) \ 102162306a36Sopenharmony_ci __ATTR(name, 0644, deadline_##name##_show, deadline_##name##_store) 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_cistatic struct elv_fs_entry deadline_attrs[] = { 102462306a36Sopenharmony_ci DD_ATTR(read_expire), 102562306a36Sopenharmony_ci DD_ATTR(write_expire), 102662306a36Sopenharmony_ci DD_ATTR(writes_starved), 102762306a36Sopenharmony_ci DD_ATTR(front_merges), 102862306a36Sopenharmony_ci DD_ATTR(async_depth), 102962306a36Sopenharmony_ci DD_ATTR(fifo_batch), 103062306a36Sopenharmony_ci DD_ATTR(prio_aging_expire), 103162306a36Sopenharmony_ci __ATTR_NULL 103262306a36Sopenharmony_ci}; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEBUG_FS 103562306a36Sopenharmony_ci#define DEADLINE_DEBUGFS_DDIR_ATTRS(prio, data_dir, name) \ 103662306a36Sopenharmony_cistatic void *deadline_##name##_fifo_start(struct seq_file *m, \ 103762306a36Sopenharmony_ci loff_t *pos) \ 103862306a36Sopenharmony_ci __acquires(&dd->lock) \ 103962306a36Sopenharmony_ci{ \ 104062306a36Sopenharmony_ci struct request_queue *q = m->private; \ 104162306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 104262306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ 104362306a36Sopenharmony_ci \ 104462306a36Sopenharmony_ci spin_lock(&dd->lock); \ 104562306a36Sopenharmony_ci return seq_list_start(&per_prio->fifo_list[data_dir], *pos); \ 104662306a36Sopenharmony_ci} \ 104762306a36Sopenharmony_ci \ 104862306a36Sopenharmony_cistatic void *deadline_##name##_fifo_next(struct seq_file *m, void *v, \ 104962306a36Sopenharmony_ci loff_t *pos) \ 105062306a36Sopenharmony_ci{ \ 105162306a36Sopenharmony_ci struct request_queue *q = m->private; \ 105262306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 105362306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ 105462306a36Sopenharmony_ci \ 105562306a36Sopenharmony_ci return seq_list_next(v, &per_prio->fifo_list[data_dir], pos); \ 105662306a36Sopenharmony_ci} \ 105762306a36Sopenharmony_ci \ 105862306a36Sopenharmony_cistatic void deadline_##name##_fifo_stop(struct seq_file *m, void *v) \ 105962306a36Sopenharmony_ci __releases(&dd->lock) \ 106062306a36Sopenharmony_ci{ \ 106162306a36Sopenharmony_ci struct request_queue *q = m->private; \ 106262306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 106362306a36Sopenharmony_ci \ 106462306a36Sopenharmony_ci spin_unlock(&dd->lock); \ 106562306a36Sopenharmony_ci} \ 106662306a36Sopenharmony_ci \ 106762306a36Sopenharmony_cistatic const struct seq_operations deadline_##name##_fifo_seq_ops = { \ 106862306a36Sopenharmony_ci .start = deadline_##name##_fifo_start, \ 106962306a36Sopenharmony_ci .next = deadline_##name##_fifo_next, \ 107062306a36Sopenharmony_ci .stop = deadline_##name##_fifo_stop, \ 107162306a36Sopenharmony_ci .show = blk_mq_debugfs_rq_show, \ 107262306a36Sopenharmony_ci}; \ 107362306a36Sopenharmony_ci \ 107462306a36Sopenharmony_cistatic int deadline_##name##_next_rq_show(void *data, \ 107562306a36Sopenharmony_ci struct seq_file *m) \ 107662306a36Sopenharmony_ci{ \ 107762306a36Sopenharmony_ci struct request_queue *q = data; \ 107862306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 107962306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ 108062306a36Sopenharmony_ci struct request *rq; \ 108162306a36Sopenharmony_ci \ 108262306a36Sopenharmony_ci rq = deadline_from_pos(per_prio, data_dir, \ 108362306a36Sopenharmony_ci per_prio->latest_pos[data_dir]); \ 108462306a36Sopenharmony_ci if (rq) \ 108562306a36Sopenharmony_ci __blk_mq_debugfs_rq_show(m, rq); \ 108662306a36Sopenharmony_ci return 0; \ 108762306a36Sopenharmony_ci} 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_RT_PRIO, DD_READ, read0); 109062306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_RT_PRIO, DD_WRITE, write0); 109162306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_BE_PRIO, DD_READ, read1); 109262306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_BE_PRIO, DD_WRITE, write1); 109362306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_IDLE_PRIO, DD_READ, read2); 109462306a36Sopenharmony_ciDEADLINE_DEBUGFS_DDIR_ATTRS(DD_IDLE_PRIO, DD_WRITE, write2); 109562306a36Sopenharmony_ci#undef DEADLINE_DEBUGFS_DDIR_ATTRS 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_cistatic int deadline_batching_show(void *data, struct seq_file *m) 109862306a36Sopenharmony_ci{ 109962306a36Sopenharmony_ci struct request_queue *q = data; 110062306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci seq_printf(m, "%u\n", dd->batching); 110362306a36Sopenharmony_ci return 0; 110462306a36Sopenharmony_ci} 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_cistatic int deadline_starved_show(void *data, struct seq_file *m) 110762306a36Sopenharmony_ci{ 110862306a36Sopenharmony_ci struct request_queue *q = data; 110962306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci seq_printf(m, "%u\n", dd->starved); 111262306a36Sopenharmony_ci return 0; 111362306a36Sopenharmony_ci} 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_cistatic int dd_async_depth_show(void *data, struct seq_file *m) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci struct request_queue *q = data; 111862306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_ci seq_printf(m, "%u\n", dd->async_depth); 112162306a36Sopenharmony_ci return 0; 112262306a36Sopenharmony_ci} 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_cistatic int dd_queued_show(void *data, struct seq_file *m) 112562306a36Sopenharmony_ci{ 112662306a36Sopenharmony_ci struct request_queue *q = data; 112762306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 112862306a36Sopenharmony_ci u32 rt, be, idle; 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci spin_lock(&dd->lock); 113162306a36Sopenharmony_ci rt = dd_queued(dd, DD_RT_PRIO); 113262306a36Sopenharmony_ci be = dd_queued(dd, DD_BE_PRIO); 113362306a36Sopenharmony_ci idle = dd_queued(dd, DD_IDLE_PRIO); 113462306a36Sopenharmony_ci spin_unlock(&dd->lock); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci seq_printf(m, "%u %u %u\n", rt, be, idle); 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci return 0; 113962306a36Sopenharmony_ci} 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci/* Number of requests owned by the block driver for a given priority. */ 114262306a36Sopenharmony_cistatic u32 dd_owned_by_driver(struct deadline_data *dd, enum dd_prio prio) 114362306a36Sopenharmony_ci{ 114462306a36Sopenharmony_ci const struct io_stats_per_prio *stats = &dd->per_prio[prio].stats; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci lockdep_assert_held(&dd->lock); 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci return stats->dispatched + stats->merged - 114962306a36Sopenharmony_ci atomic_read(&stats->completed); 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic int dd_owned_by_driver_show(void *data, struct seq_file *m) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci struct request_queue *q = data; 115562306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; 115662306a36Sopenharmony_ci u32 rt, be, idle; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci spin_lock(&dd->lock); 115962306a36Sopenharmony_ci rt = dd_owned_by_driver(dd, DD_RT_PRIO); 116062306a36Sopenharmony_ci be = dd_owned_by_driver(dd, DD_BE_PRIO); 116162306a36Sopenharmony_ci idle = dd_owned_by_driver(dd, DD_IDLE_PRIO); 116262306a36Sopenharmony_ci spin_unlock(&dd->lock); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci seq_printf(m, "%u %u %u\n", rt, be, idle); 116562306a36Sopenharmony_ci 116662306a36Sopenharmony_ci return 0; 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci#define DEADLINE_DISPATCH_ATTR(prio) \ 117062306a36Sopenharmony_cistatic void *deadline_dispatch##prio##_start(struct seq_file *m, \ 117162306a36Sopenharmony_ci loff_t *pos) \ 117262306a36Sopenharmony_ci __acquires(&dd->lock) \ 117362306a36Sopenharmony_ci{ \ 117462306a36Sopenharmony_ci struct request_queue *q = m->private; \ 117562306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 117662306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ 117762306a36Sopenharmony_ci \ 117862306a36Sopenharmony_ci spin_lock(&dd->lock); \ 117962306a36Sopenharmony_ci return seq_list_start(&per_prio->dispatch, *pos); \ 118062306a36Sopenharmony_ci} \ 118162306a36Sopenharmony_ci \ 118262306a36Sopenharmony_cistatic void *deadline_dispatch##prio##_next(struct seq_file *m, \ 118362306a36Sopenharmony_ci void *v, loff_t *pos) \ 118462306a36Sopenharmony_ci{ \ 118562306a36Sopenharmony_ci struct request_queue *q = m->private; \ 118662306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 118762306a36Sopenharmony_ci struct dd_per_prio *per_prio = &dd->per_prio[prio]; \ 118862306a36Sopenharmony_ci \ 118962306a36Sopenharmony_ci return seq_list_next(v, &per_prio->dispatch, pos); \ 119062306a36Sopenharmony_ci} \ 119162306a36Sopenharmony_ci \ 119262306a36Sopenharmony_cistatic void deadline_dispatch##prio##_stop(struct seq_file *m, void *v) \ 119362306a36Sopenharmony_ci __releases(&dd->lock) \ 119462306a36Sopenharmony_ci{ \ 119562306a36Sopenharmony_ci struct request_queue *q = m->private; \ 119662306a36Sopenharmony_ci struct deadline_data *dd = q->elevator->elevator_data; \ 119762306a36Sopenharmony_ci \ 119862306a36Sopenharmony_ci spin_unlock(&dd->lock); \ 119962306a36Sopenharmony_ci} \ 120062306a36Sopenharmony_ci \ 120162306a36Sopenharmony_cistatic const struct seq_operations deadline_dispatch##prio##_seq_ops = { \ 120262306a36Sopenharmony_ci .start = deadline_dispatch##prio##_start, \ 120362306a36Sopenharmony_ci .next = deadline_dispatch##prio##_next, \ 120462306a36Sopenharmony_ci .stop = deadline_dispatch##prio##_stop, \ 120562306a36Sopenharmony_ci .show = blk_mq_debugfs_rq_show, \ 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_ciDEADLINE_DISPATCH_ATTR(0); 120962306a36Sopenharmony_ciDEADLINE_DISPATCH_ATTR(1); 121062306a36Sopenharmony_ciDEADLINE_DISPATCH_ATTR(2); 121162306a36Sopenharmony_ci#undef DEADLINE_DISPATCH_ATTR 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci#define DEADLINE_QUEUE_DDIR_ATTRS(name) \ 121462306a36Sopenharmony_ci {#name "_fifo_list", 0400, \ 121562306a36Sopenharmony_ci .seq_ops = &deadline_##name##_fifo_seq_ops} 121662306a36Sopenharmony_ci#define DEADLINE_NEXT_RQ_ATTR(name) \ 121762306a36Sopenharmony_ci {#name "_next_rq", 0400, deadline_##name##_next_rq_show} 121862306a36Sopenharmony_cistatic const struct blk_mq_debugfs_attr deadline_queue_debugfs_attrs[] = { 121962306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(read0), 122062306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(write0), 122162306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(read1), 122262306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(write1), 122362306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(read2), 122462306a36Sopenharmony_ci DEADLINE_QUEUE_DDIR_ATTRS(write2), 122562306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(read0), 122662306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(write0), 122762306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(read1), 122862306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(write1), 122962306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(read2), 123062306a36Sopenharmony_ci DEADLINE_NEXT_RQ_ATTR(write2), 123162306a36Sopenharmony_ci {"batching", 0400, deadline_batching_show}, 123262306a36Sopenharmony_ci {"starved", 0400, deadline_starved_show}, 123362306a36Sopenharmony_ci {"async_depth", 0400, dd_async_depth_show}, 123462306a36Sopenharmony_ci {"dispatch0", 0400, .seq_ops = &deadline_dispatch0_seq_ops}, 123562306a36Sopenharmony_ci {"dispatch1", 0400, .seq_ops = &deadline_dispatch1_seq_ops}, 123662306a36Sopenharmony_ci {"dispatch2", 0400, .seq_ops = &deadline_dispatch2_seq_ops}, 123762306a36Sopenharmony_ci {"owned_by_driver", 0400, dd_owned_by_driver_show}, 123862306a36Sopenharmony_ci {"queued", 0400, dd_queued_show}, 123962306a36Sopenharmony_ci {}, 124062306a36Sopenharmony_ci}; 124162306a36Sopenharmony_ci#undef DEADLINE_QUEUE_DDIR_ATTRS 124262306a36Sopenharmony_ci#endif 124362306a36Sopenharmony_ci 124462306a36Sopenharmony_cistatic struct elevator_type mq_deadline = { 124562306a36Sopenharmony_ci .ops = { 124662306a36Sopenharmony_ci .depth_updated = dd_depth_updated, 124762306a36Sopenharmony_ci .limit_depth = dd_limit_depth, 124862306a36Sopenharmony_ci .insert_requests = dd_insert_requests, 124962306a36Sopenharmony_ci .dispatch_request = dd_dispatch_request, 125062306a36Sopenharmony_ci .prepare_request = dd_prepare_request, 125162306a36Sopenharmony_ci .finish_request = dd_finish_request, 125262306a36Sopenharmony_ci .next_request = elv_rb_latter_request, 125362306a36Sopenharmony_ci .former_request = elv_rb_former_request, 125462306a36Sopenharmony_ci .bio_merge = dd_bio_merge, 125562306a36Sopenharmony_ci .request_merge = dd_request_merge, 125662306a36Sopenharmony_ci .requests_merged = dd_merged_requests, 125762306a36Sopenharmony_ci .request_merged = dd_request_merged, 125862306a36Sopenharmony_ci .has_work = dd_has_work, 125962306a36Sopenharmony_ci .init_sched = dd_init_sched, 126062306a36Sopenharmony_ci .exit_sched = dd_exit_sched, 126162306a36Sopenharmony_ci .init_hctx = dd_init_hctx, 126262306a36Sopenharmony_ci }, 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci#ifdef CONFIG_BLK_DEBUG_FS 126562306a36Sopenharmony_ci .queue_debugfs_attrs = deadline_queue_debugfs_attrs, 126662306a36Sopenharmony_ci#endif 126762306a36Sopenharmony_ci .elevator_attrs = deadline_attrs, 126862306a36Sopenharmony_ci .elevator_name = "mq-deadline", 126962306a36Sopenharmony_ci .elevator_alias = "deadline", 127062306a36Sopenharmony_ci .elevator_features = ELEVATOR_F_ZBD_SEQ_WRITE, 127162306a36Sopenharmony_ci .elevator_owner = THIS_MODULE, 127262306a36Sopenharmony_ci}; 127362306a36Sopenharmony_ciMODULE_ALIAS("mq-deadline-iosched"); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_cistatic int __init deadline_init(void) 127662306a36Sopenharmony_ci{ 127762306a36Sopenharmony_ci return elv_register(&mq_deadline); 127862306a36Sopenharmony_ci} 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_cistatic void __exit deadline_exit(void) 128162306a36Sopenharmony_ci{ 128262306a36Sopenharmony_ci elv_unregister(&mq_deadline); 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_cimodule_init(deadline_init); 128662306a36Sopenharmony_cimodule_exit(deadline_exit); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ciMODULE_AUTHOR("Jens Axboe, Damien Le Moal and Bart Van Assche"); 128962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 129062306a36Sopenharmony_ciMODULE_DESCRIPTION("MQ deadline IO scheduler"); 1291