diff options
| author | Jens Axboe <axboe@fb.com> | 2017-01-17 08:03:22 -0500 |
|---|---|---|
| committer | Jens Axboe <axboe@fb.com> | 2017-01-17 12:04:20 -0500 |
| commit | bd166ef183c263c5ced656d49ef19c7da4adc774 (patch) | |
| tree | 449bbd3b4e671b370b96e3846b2281116e7089e9 /include | |
| parent | 2af8cbe30531eca73c8f3ba277f155fc0020b01a (diff) | |
blk-mq-sched: add framework for MQ capable IO schedulers
This adds a set of hooks that intercepts the blk-mq path of
allocating/inserting/issuing/completing requests, allowing
us to develop a scheduler within that framework.
We reuse the existing elevator scheduler API on the registration
side, but augment that with the scheduler flagging support for
the blk-mq interfce, and with a separate set of ops hooks for MQ
devices.
We split driver and scheduler tags, so we can run the scheduling
independently of device queue depth.
Signed-off-by: Jens Axboe <axboe@fb.com>
Reviewed-by: Bart Van Assche <bart.vanassche@sandisk.com>
Reviewed-by: Omar Sandoval <osandov@fb.com>
Diffstat (limited to 'include')
| -rw-r--r-- | include/linux/blk-mq.h | 5 | ||||
| -rw-r--r-- | include/linux/blkdev.h | 4 | ||||
| -rw-r--r-- | include/linux/elevator.h | 32 |
3 files changed, 39 insertions, 2 deletions
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h index 2686f9e7302a..63569eb46d15 100644 --- a/include/linux/blk-mq.h +++ b/include/linux/blk-mq.h | |||
| @@ -22,6 +22,7 @@ struct blk_mq_hw_ctx { | |||
| 22 | 22 | ||
| 23 | unsigned long flags; /* BLK_MQ_F_* flags */ | 23 | unsigned long flags; /* BLK_MQ_F_* flags */ |
| 24 | 24 | ||
| 25 | void *sched_data; | ||
| 25 | struct request_queue *queue; | 26 | struct request_queue *queue; |
| 26 | struct blk_flush_queue *fq; | 27 | struct blk_flush_queue *fq; |
| 27 | 28 | ||
| @@ -35,6 +36,7 @@ struct blk_mq_hw_ctx { | |||
| 35 | atomic_t wait_index; | 36 | atomic_t wait_index; |
| 36 | 37 | ||
| 37 | struct blk_mq_tags *tags; | 38 | struct blk_mq_tags *tags; |
| 39 | struct blk_mq_tags *sched_tags; | ||
| 38 | 40 | ||
| 39 | struct srcu_struct queue_rq_srcu; | 41 | struct srcu_struct queue_rq_srcu; |
| 40 | 42 | ||
| @@ -156,6 +158,7 @@ enum { | |||
| 156 | 158 | ||
| 157 | BLK_MQ_S_STOPPED = 0, | 159 | BLK_MQ_S_STOPPED = 0, |
| 158 | BLK_MQ_S_TAG_ACTIVE = 1, | 160 | BLK_MQ_S_TAG_ACTIVE = 1, |
| 161 | BLK_MQ_S_SCHED_RESTART = 2, | ||
| 159 | 162 | ||
| 160 | BLK_MQ_MAX_DEPTH = 10240, | 163 | BLK_MQ_MAX_DEPTH = 10240, |
| 161 | 164 | ||
| @@ -179,13 +182,13 @@ void blk_mq_free_tag_set(struct blk_mq_tag_set *set); | |||
| 179 | 182 | ||
| 180 | void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule); | 183 | void blk_mq_flush_plug_list(struct blk_plug *plug, bool from_schedule); |
| 181 | 184 | ||
| 182 | void blk_mq_insert_request(struct request *, bool, bool, bool); | ||
| 183 | void blk_mq_free_request(struct request *rq); | 185 | void blk_mq_free_request(struct request *rq); |
| 184 | bool blk_mq_can_queue(struct blk_mq_hw_ctx *); | 186 | bool blk_mq_can_queue(struct blk_mq_hw_ctx *); |
| 185 | 187 | ||
| 186 | enum { | 188 | enum { |
| 187 | BLK_MQ_REQ_NOWAIT = (1 << 0), /* return when out of requests */ | 189 | BLK_MQ_REQ_NOWAIT = (1 << 0), /* return when out of requests */ |
| 188 | BLK_MQ_REQ_RESERVED = (1 << 1), /* allocate from reserved pool */ | 190 | BLK_MQ_REQ_RESERVED = (1 << 1), /* allocate from reserved pool */ |
| 191 | BLK_MQ_REQ_INTERNAL = (1 << 2), /* allocate internal/sched tag */ | ||
| 189 | }; | 192 | }; |
| 190 | 193 | ||
| 191 | struct request *blk_mq_alloc_request(struct request_queue *q, int rw, | 194 | struct request *blk_mq_alloc_request(struct request_queue *q, int rw, |
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2e99d659b0f1..25564857f5f8 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h | |||
| @@ -154,6 +154,7 @@ struct request { | |||
| 154 | 154 | ||
| 155 | /* the following two fields are internal, NEVER access directly */ | 155 | /* the following two fields are internal, NEVER access directly */ |
| 156 | unsigned int __data_len; /* total data len */ | 156 | unsigned int __data_len; /* total data len */ |
| 157 | int tag; | ||
| 157 | sector_t __sector; /* sector cursor */ | 158 | sector_t __sector; /* sector cursor */ |
| 158 | 159 | ||
| 159 | struct bio *bio; | 160 | struct bio *bio; |
| @@ -220,9 +221,10 @@ struct request { | |||
| 220 | 221 | ||
| 221 | unsigned short ioprio; | 222 | unsigned short ioprio; |
| 222 | 223 | ||
| 224 | int internal_tag; | ||
| 225 | |||
| 223 | void *special; /* opaque pointer available for LLD use */ | 226 | void *special; /* opaque pointer available for LLD use */ |
| 224 | 227 | ||
| 225 | int tag; | ||
| 226 | int errors; | 228 | int errors; |
| 227 | 229 | ||
| 228 | /* | 230 | /* |
diff --git a/include/linux/elevator.h b/include/linux/elevator.h index 2a9e966eed03..ecb96fd67c6d 100644 --- a/include/linux/elevator.h +++ b/include/linux/elevator.h | |||
| @@ -77,6 +77,34 @@ struct elevator_ops | |||
| 77 | elevator_registered_fn *elevator_registered_fn; | 77 | elevator_registered_fn *elevator_registered_fn; |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | struct blk_mq_alloc_data; | ||
| 81 | struct blk_mq_hw_ctx; | ||
| 82 | |||
| 83 | struct elevator_mq_ops { | ||
| 84 | int (*init_sched)(struct request_queue *, struct elevator_type *); | ||
| 85 | void (*exit_sched)(struct elevator_queue *); | ||
| 86 | |||
| 87 | bool (*allow_merge)(struct request_queue *, struct request *, struct bio *); | ||
| 88 | bool (*bio_merge)(struct blk_mq_hw_ctx *, struct bio *); | ||
| 89 | int (*request_merge)(struct request_queue *q, struct request **, struct bio *); | ||
| 90 | void (*request_merged)(struct request_queue *, struct request *, int); | ||
| 91 | void (*requests_merged)(struct request_queue *, struct request *, struct request *); | ||
| 92 | struct request *(*get_request)(struct request_queue *, unsigned int, struct blk_mq_alloc_data *); | ||
| 93 | void (*put_request)(struct request *); | ||
| 94 | void (*insert_requests)(struct blk_mq_hw_ctx *, struct list_head *, bool); | ||
| 95 | void (*dispatch_requests)(struct blk_mq_hw_ctx *, struct list_head *); | ||
| 96 | bool (*has_work)(struct blk_mq_hw_ctx *); | ||
| 97 | void (*completed_request)(struct blk_mq_hw_ctx *, struct request *); | ||
| 98 | void (*started_request)(struct request *); | ||
| 99 | void (*requeue_request)(struct request *); | ||
| 100 | struct request *(*former_request)(struct request_queue *, struct request *); | ||
| 101 | struct request *(*next_request)(struct request_queue *, struct request *); | ||
| 102 | int (*get_rq_priv)(struct request_queue *, struct request *); | ||
| 103 | void (*put_rq_priv)(struct request_queue *, struct request *); | ||
| 104 | void (*init_icq)(struct io_cq *); | ||
| 105 | void (*exit_icq)(struct io_cq *); | ||
| 106 | }; | ||
| 107 | |||
| 80 | #define ELV_NAME_MAX (16) | 108 | #define ELV_NAME_MAX (16) |
| 81 | 109 | ||
| 82 | struct elv_fs_entry { | 110 | struct elv_fs_entry { |
| @@ -96,12 +124,14 @@ struct elevator_type | |||
| 96 | /* fields provided by elevator implementation */ | 124 | /* fields provided by elevator implementation */ |
| 97 | union { | 125 | union { |
| 98 | struct elevator_ops sq; | 126 | struct elevator_ops sq; |
| 127 | struct elevator_mq_ops mq; | ||
| 99 | } ops; | 128 | } ops; |
| 100 | size_t icq_size; /* see iocontext.h */ | 129 | size_t icq_size; /* see iocontext.h */ |
| 101 | size_t icq_align; /* ditto */ | 130 | size_t icq_align; /* ditto */ |
| 102 | struct elv_fs_entry *elevator_attrs; | 131 | struct elv_fs_entry *elevator_attrs; |
| 103 | char elevator_name[ELV_NAME_MAX]; | 132 | char elevator_name[ELV_NAME_MAX]; |
| 104 | struct module *elevator_owner; | 133 | struct module *elevator_owner; |
| 134 | bool uses_mq; | ||
| 105 | 135 | ||
| 106 | /* managed by elevator core */ | 136 | /* managed by elevator core */ |
| 107 | char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */ | 137 | char icq_cache_name[ELV_NAME_MAX + 5]; /* elvname + "_io_cq" */ |
| @@ -125,6 +155,7 @@ struct elevator_queue | |||
| 125 | struct kobject kobj; | 155 | struct kobject kobj; |
| 126 | struct mutex sysfs_lock; | 156 | struct mutex sysfs_lock; |
| 127 | unsigned int registered:1; | 157 | unsigned int registered:1; |
| 158 | unsigned int uses_mq:1; | ||
| 128 | DECLARE_HASHTABLE(hash, ELV_HASH_BITS); | 159 | DECLARE_HASHTABLE(hash, ELV_HASH_BITS); |
| 129 | }; | 160 | }; |
| 130 | 161 | ||
| @@ -141,6 +172,7 @@ extern void elv_merge_requests(struct request_queue *, struct request *, | |||
| 141 | extern void elv_merged_request(struct request_queue *, struct request *, int); | 172 | extern void elv_merged_request(struct request_queue *, struct request *, int); |
| 142 | extern void elv_bio_merged(struct request_queue *q, struct request *, | 173 | extern void elv_bio_merged(struct request_queue *q, struct request *, |
| 143 | struct bio *); | 174 | struct bio *); |
| 175 | extern bool elv_attempt_insert_merge(struct request_queue *, struct request *); | ||
| 144 | extern void elv_requeue_request(struct request_queue *, struct request *); | 176 | extern void elv_requeue_request(struct request_queue *, struct request *); |
| 145 | extern struct request *elv_former_request(struct request_queue *, struct request *); | 177 | extern struct request *elv_former_request(struct request_queue *, struct request *); |
| 146 | extern struct request *elv_latter_request(struct request_queue *, struct request *); | 178 | extern struct request *elv_latter_request(struct request_queue *, struct request *); |
