summaryrefslogtreecommitdiffstatshomepage
path: root/block/blk-rq-qos.c
diff options
context:
space:
mode:
authorJosef Bacik <josef@toxicpanda.com>2018-12-04 08:59:02 -0900
committerJens Axboe <axboe@kernel.dk>2018-12-07 20:26:38 -0900
commit84f603246db9703aca05aad58b94a54dfbf44327 (patch)
treea2235d4f431e619f04292aea0349399ab4b8da68 /block/blk-rq-qos.c
parent7754f669ffde3919e398a9e591cd7510d6cf4e73 (diff)
downloadlinux-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.c86
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
179struct 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
188static 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 */
223void 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
179void rq_qos_exit(struct request_queue *q) 265void rq_qos_exit(struct request_queue *q)
180{ 266{
181 while (q->rq_qos) { 267 while (q->rq_qos) {