diff options
| author | Josef Bacik <josef@toxicpanda.com> | 2018-12-04 08:59:02 -0900 |
|---|---|---|
| committer | Jens Axboe <axboe@kernel.dk> | 2018-12-07 20:26:38 -0900 |
| commit | 84f603246db9703aca05aad58b94a54dfbf44327 (patch) | |
| tree | a2235d4f431e619f04292aea0349399ab4b8da68 /block/blk-rq-qos.c | |
| parent | 7754f669ffde3919e398a9e591cd7510d6cf4e73 (diff) | |
| download | linux-stable-84f603246db9703aca05aad58b94a54dfbf44327.tar.gz linux-stable-84f603246db9703aca05aad58b94a54dfbf44327.tar.bz2 linux-stable-84f603246db9703aca05aad58b94a54dfbf44327.tar.xz linux-stable-84f603246db9703aca05aad58b94a54dfbf44327.zip | |
block: add rq_qos_wait to rq_qos
Originally when I split out the common code from blk-wbt into rq_qos I
left the wbt_wait() where it was and simply copied and modified it
slightly to work for io-latency. However they are both basically the
same thing, and as time has gone on wbt_wait() has ended up much smarter
and kinder than it was when I copied it into io-latency, which means
io-latency has lost out on these improvements.
Since they are the same thing essentially except for a few minor things,
create rq_qos_wait() that replicates what wbt_wait() currently does with
callbacks that can be passed in for the snowflakes to do their own thing
as appropriate.
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'block/blk-rq-qos.c')
| -rw-r--r-- | block/blk-rq-qos.c | 86 |
1 files changed, 86 insertions, 0 deletions
diff --git a/block/blk-rq-qos.c b/block/blk-rq-qos.c index 80f603b76f61..e932ef9d2718 100644 --- a/block/blk-rq-qos.c +++ b/block/blk-rq-qos.c | |||
| @@ -176,6 +176,92 @@ void rq_depth_scale_down(struct rq_depth *rqd, bool hard_throttle) | |||
| 176 | rq_depth_calc_max_depth(rqd); | 176 | rq_depth_calc_max_depth(rqd); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | struct rq_qos_wait_data { | ||
| 180 | struct wait_queue_entry wq; | ||
| 181 | struct task_struct *task; | ||
| 182 | struct rq_wait *rqw; | ||
| 183 | acquire_inflight_cb_t *cb; | ||
| 184 | void *private_data; | ||
| 185 | bool got_token; | ||
| 186 | }; | ||
| 187 | |||
| 188 | static int rq_qos_wake_function(struct wait_queue_entry *curr, | ||
| 189 | unsigned int mode, int wake_flags, void *key) | ||
| 190 | { | ||
| 191 | struct rq_qos_wait_data *data = container_of(curr, | ||
| 192 | struct rq_qos_wait_data, | ||
| 193 | wq); | ||
| 194 | |||
| 195 | /* | ||
| 196 | * If we fail to get a budget, return -1 to interrupt the wake up loop | ||
| 197 | * in __wake_up_common. | ||
| 198 | */ | ||
| 199 | if (!data->cb(data->rqw, data->private_data)) | ||
| 200 | return -1; | ||
| 201 | |||
| 202 | data->got_token = true; | ||
| 203 | list_del_init(&curr->entry); | ||
| 204 | wake_up_process(data->task); | ||
| 205 | return 1; | ||
| 206 | } | ||
| 207 | |||
| 208 | /** | ||
| 209 | * rq_qos_wait - throttle on a rqw if we need to | ||
| 210 | * @private_data - caller provided specific data | ||
| 211 | * @acquire_inflight_cb - inc the rqw->inflight counter if we can | ||
| 212 | * @cleanup_cb - the callback to cleanup in case we race with a waker | ||
| 213 | * | ||
| 214 | * This provides a uniform place for the rq_qos users to do their throttling. | ||
| 215 | * Since you can end up with a lot of things sleeping at once, this manages the | ||
| 216 | * waking up based on the resources available. The acquire_inflight_cb should | ||
| 217 | * inc the rqw->inflight if we have the ability to do so, or return false if not | ||
| 218 | * and then we will sleep until the room becomes available. | ||
| 219 | * | ||
| 220 | * cleanup_cb is in case that we race with a waker and need to cleanup the | ||
| 221 | * inflight count accordingly. | ||
| 222 | */ | ||
| 223 | void rq_qos_wait(struct rq_wait *rqw, void *private_data, | ||
| 224 | acquire_inflight_cb_t *acquire_inflight_cb, | ||
| 225 | cleanup_cb_t *cleanup_cb) | ||
| 226 | { | ||
| 227 | struct rq_qos_wait_data data = { | ||
| 228 | .wq = { | ||
| 229 | .func = rq_qos_wake_function, | ||
| 230 | .entry = LIST_HEAD_INIT(data.wq.entry), | ||
| 231 | }, | ||
| 232 | .task = current, | ||
| 233 | .rqw = rqw, | ||
| 234 | .cb = acquire_inflight_cb, | ||
| 235 | .private_data = private_data, | ||
| 236 | }; | ||
| 237 | bool has_sleeper; | ||
| 238 | |||
| 239 | has_sleeper = wq_has_sleeper(&rqw->wait); | ||
| 240 | if (!has_sleeper && acquire_inflight_cb(rqw, private_data)) | ||
| 241 | return; | ||
| 242 | |||
| 243 | prepare_to_wait_exclusive(&rqw->wait, &data.wq, TASK_UNINTERRUPTIBLE); | ||
| 244 | do { | ||
| 245 | if (data.got_token) | ||
| 246 | break; | ||
| 247 | if (!has_sleeper && acquire_inflight_cb(rqw, private_data)) { | ||
| 248 | finish_wait(&rqw->wait, &data.wq); | ||
| 249 | |||
| 250 | /* | ||
| 251 | * We raced with wbt_wake_function() getting a token, | ||
| 252 | * which means we now have two. Put our local token | ||
| 253 | * and wake anyone else potentially waiting for one. | ||
| 254 | */ | ||
| 255 | if (data.got_token) | ||
| 256 | cleanup_cb(rqw, private_data); | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | io_schedule(); | ||
| 260 | has_sleeper = false; | ||
| 261 | } while (1); | ||
| 262 | finish_wait(&rqw->wait, &data.wq); | ||
| 263 | } | ||
| 264 | |||
| 179 | void rq_qos_exit(struct request_queue *q) | 265 | void rq_qos_exit(struct request_queue *q) |
| 180 | { | 266 | { |
| 181 | while (q->rq_qos) { | 267 | while (q->rq_qos) { |
