| 1 |
|
| 2 | #ifndef _ELEVATOR_H
|
| 3 | #define _ELEVATOR_H
|
| 4 |
|
| 5 | #include <linux/percpu.h>
|
| 6 | #include <linux/hashtable.h>
|
| 7 | #include "blk-mq.h"
|
| 8 |
|
| 9 | struct io_cq;
|
| 10 | struct elevator_type;
|
| 11 | struct blk_mq_debugfs_attr;
|
| 12 |
|
| 13 | |
| 14 | * Return values from elevator merger
|
| 15 |
|
| 16 | enum elv_merge {
|
| 17 | ELEVATOR_NO_MERGE = 0,
|
| 18 | ELEVATOR_FRONT_MERGE = 1,
|
| 19 | ELEVATOR_BACK_MERGE = 2,
|
| 20 | ELEVATOR_DISCARD_MERGE = 3,
|
| 21 | };
|
| 22 |
|
| 23 | struct blk_mq_alloc_data;
|
| 24 | struct blk_mq_hw_ctx;
|
| 25 |
|
| 26 | struct elevator_tags {
|
| 27 |
|
| 28 | unsigned int nr_hw_queues;
|
| 29 |
|
| 30 | unsigned int nr_requests;
|
| 31 |
|
| 32 | struct blk_mq_tags *tags[];
|
| 33 | };
|
| 34 |
|
| 35 | struct elevator_resources {
|
| 36 |
|
| 37 | void *data;
|
| 38 |
|
| 39 | struct elevator_tags *et;
|
| 40 | };
|
| 41 |
|
| 42 |
|
| 43 | struct elv_change_ctx {
|
| 44 | const char *name;
|
| 45 | bool no_uevent;
|
| 46 |
|
| 47 |
|
| 48 | struct elevator_queue *old;
|
| 49 |
|
| 50 | struct elevator_queue *new;
|
| 51 |
|
| 52 | struct elevator_type *type;
|
| 53 |
|
| 54 | struct elevator_resources res;
|
| 55 | };
|
| 56 |
|
| 57 | struct elevator_mq_ops {
|
| 58 | int (*init_sched)(struct request_queue *, struct elevator_queue *);
|
| 59 | void (*exit_sched)(struct elevator_queue *);
|
| 60 | int (*init_hctx)(struct blk_mq_hw_ctx *, unsigned int);
|
| 61 | void (*exit_hctx)(struct blk_mq_hw_ctx *, unsigned int);
|
| 62 | void (*depth_updated)(struct request_queue *);
|
| 63 | void *(*alloc_sched_data)(struct request_queue *);
|
| 64 | void (*free_sched_data)(void *);
|
| 65 |
|
| 66 | bool (*allow_merge)(struct request_queue *, struct request *, struct bio *);
|
| 67 | bool (*bio_merge)(struct request_queue *, struct bio *, unsigned int);
|
| 68 | int (*request_merge)(struct request_queue *q, struct request **, struct bio *);
|
| 69 | void (*request_merged)(struct request_queue *, struct request *, enum elv_merge);
|
| 70 | void (*requests_merged)(struct request_queue *, struct request *, struct request *);
|
| 71 | void (*limit_depth)(blk_opf_t, struct blk_mq_alloc_data *);
|
| 72 | void (*prepare_request)(struct request *);
|
| 73 | void (*finish_request)(struct request *);
|
| 74 | void (*insert_requests)(struct blk_mq_hw_ctx *hctx, struct list_head *list,
|
| 75 | blk_insert_t flags);
|
| 76 | struct request *(*dispatch_request)(struct blk_mq_hw_ctx *);
|
| 77 | bool (*has_work)(struct blk_mq_hw_ctx *);
|
| 78 | void (*completed_request)(struct request *, u64);
|
| 79 | void (*requeue_request)(struct request *);
|
| 80 | struct request *(*former_request)(struct request_queue *, struct request *);
|
| 81 | struct request *(*next_request)(struct request_queue *, struct request *);
|
| 82 | void (*init_icq)(struct io_cq *);
|
| 83 | void (*exit_icq)(struct io_cq *);
|
| 84 | };
|
| 85 |
|
| 86 | #define ELV_NAME_MAX (16)
|
| 87 |
|
| 88 | struct elv_fs_entry {
|
| 89 | struct attribute attr;
|
| 90 | ssize_t (*show)(struct elevator_queue *, char *);
|
| 91 | ssize_t (*store)(struct elevator_queue *, const char *, size_t);
|
| 92 | };
|
| 93 |
|
| 94 | |
| 95 | * identifies an elevator type, such as AS or deadline
|
| 96 |
|
| 97 | struct elevator_type
|
| 98 | {
|
| 99 |
|
| 100 | struct kmem_cache *icq_cache;
|
| 101 |
|
| 102 |
|
| 103 | struct elevator_mq_ops ops;
|
| 104 |
|
| 105 | size_t icq_size;
|
| 106 | size_t icq_align;
|
| 107 | const struct elv_fs_entry *elevator_attrs;
|
| 108 | const char *elevator_name;
|
| 109 | const char *elevator_alias;
|
| 110 | struct module *elevator_owner;
|
| 111 | #ifdef CONFIG_BLK_DEBUG_FS
|
| 112 | const struct blk_mq_debugfs_attr *queue_debugfs_attrs;
|
| 113 | const struct blk_mq_debugfs_attr *hctx_debugfs_attrs;
|
| 114 | #endif
|
| 115 |
|
| 116 |
|
| 117 | char icq_cache_name[ELV_NAME_MAX + 6];
|
| 118 | struct list_head list;
|
| 119 | };
|
| 120 |
|
| 121 | static inline bool elevator_tryget(struct elevator_type *e)
|
| 122 | {
|
| 123 | return try_module_get(e->elevator_owner);
|
| 124 | }
|
| 125 |
|
| 126 | static inline void __elevator_get(struct elevator_type *e)
|
| 127 | {
|
| 128 | __module_get(e->elevator_owner);
|
| 129 | }
|
| 130 |
|
| 131 | static inline void elevator_put(struct elevator_type *e)
|
| 132 | {
|
| 133 | module_put(e->elevator_owner);
|
| 134 | }
|
| 135 |
|
| 136 | #define ELV_HASH_BITS 6
|
| 137 |
|
| 138 | void elv_rqhash_del(struct request_queue *q, struct request *rq);
|
| 139 | void elv_rqhash_add(struct request_queue *q, struct request *rq);
|
| 140 | void elv_rqhash_reposition(struct request_queue *q, struct request *rq);
|
| 141 | struct request *elv_rqhash_find(struct request_queue *q, sector_t offset);
|
| 142 |
|
| 143 | |
| 144 | * each queue has an elevator_queue associated with it
|
| 145 |
|
| 146 | struct elevator_queue
|
| 147 | {
|
| 148 | struct elevator_type *type;
|
| 149 | struct elevator_tags *et;
|
| 150 | void *elevator_data;
|
| 151 | struct kobject kobj;
|
| 152 | struct mutex sysfs_lock;
|
| 153 | unsigned long flags;
|
| 154 | DECLARE_HASHTABLE(hash, ELV_HASH_BITS);
|
| 155 | };
|
| 156 |
|
| 157 | #define ELEVATOR_FLAG_REGISTERED 0
|
| 158 | #define ELEVATOR_FLAG_DYING 1
|
| 159 |
|
| 160 | |
| 161 | * block elevator interface
|
| 162 |
|
| 163 | extern enum elv_merge elv_merge(struct request_queue *, struct request **,
|
| 164 | struct bio *);
|
| 165 | extern void elv_merge_requests(struct request_queue *, struct request *,
|
| 166 | struct request *);
|
| 167 | extern void elv_merged_request(struct request_queue *, struct request *,
|
| 168 | enum elv_merge);
|
| 169 | extern bool elv_attempt_insert_merge(struct request_queue *, struct request *,
|
| 170 | struct list_head *);
|
| 171 | extern struct request *elv_former_request(struct request_queue *, struct request *);
|
| 172 | extern struct request *elv_latter_request(struct request_queue *, struct request *);
|
| 173 |
|
| 174 | |
| 175 | * io scheduler registration
|
| 176 |
|
| 177 | extern int elv_register(struct elevator_type *);
|
| 178 | extern void elv_unregister(struct elevator_type *);
|
| 179 |
|
| 180 | |
| 181 | * io scheduler sysfs switching
|
| 182 |
|
| 183 | ssize_t elv_iosched_show(struct gendisk *disk, char *page);
|
| 184 | ssize_t elv_iosched_store(struct gendisk *disk, const char *page, size_t count);
|
| 185 |
|
| 186 | extern bool elv_bio_merge_ok(struct request *, struct bio *);
|
| 187 | struct elevator_queue *elevator_alloc(struct request_queue *,
|
| 188 | struct elevator_type *, struct elevator_resources *);
|
| 189 |
|
| 190 | |
| 191 | * Helper functions.
|
| 192 |
|
| 193 | extern struct request *elv_rb_former_request(struct request_queue *, struct request *);
|
| 194 | extern struct request *elv_rb_latter_request(struct request_queue *, struct request *);
|
| 195 |
|
| 196 | |
| 197 | * rb support functions.
|
| 198 |
|
| 199 | extern void elv_rb_add(struct rb_root *, struct request *);
|
| 200 | extern void elv_rb_del(struct rb_root *, struct request *);
|
| 201 | extern struct request *elv_rb_find(struct rb_root *, sector_t);
|
| 202 |
|
| 203 | |
| 204 | * Insertion selection
|
| 205 |
|
| 206 | #define ELEVATOR_INSERT_FRONT 1
|
| 207 | #define ELEVATOR_INSERT_BACK 2
|
| 208 | #define ELEVATOR_INSERT_SORT 3
|
| 209 | #define ELEVATOR_INSERT_REQUEUE 4
|
| 210 | #define ELEVATOR_INSERT_FLUSH 5
|
| 211 | #define ELEVATOR_INSERT_SORT_MERGE 6
|
| 212 |
|
| 213 | #define rb_entry_rq(node) rb_entry((node), struct request, rb_node)
|
| 214 |
|
| 215 | #define rq_entry_fifo(ptr) list_entry((ptr), struct request, queuelist)
|
| 216 | #define rq_fifo_clear(rq) list_del_init(&(rq)->queuelist)
|
| 217 |
|
| 218 | void blk_mq_sched_reg_debugfs(struct request_queue *q);
|
| 219 | void blk_mq_sched_unreg_debugfs(struct request_queue *q);
|
| 220 |
|
| 221 | #endif
|