diff options
author | Shaohua Li <shli@fb.com> | 2017-05-17 16:07:26 -0400 |
---|---|---|
committer | Jens Axboe <axboe@fb.com> | 2017-05-22 16:47:12 -0400 |
commit | 9bb67aeb96784527dbc784c7a1b234461299363c (patch) | |
tree | e2146e228a7a161b463429ff1f4723c985db19ce /block/blk-throttle.c | |
parent | 4cff729f62d1bd433178f1ffe09db5718835e925 (diff) |
blk-throttle: respect 0 bps/iops settings for io.low
If a cgroup with low limit 0 for both bps/iops, the cgroup's low limit
is ignored and we throttle the cgroup with its max limit. In this way,
other cgroups with a low limit will not get protected. To fix this, we
don't do the exception any more. cgroup will be throttled to a limit 0
if it uese default setting. To avoid completed stall, we give such
cgroup tiny IO resources.
Signed-off-by: Shaohua Li <shli@fb.com>
Acked-by: Tejun Heo <tj@kernel.org>
Signed-off-by: Jens Axboe <axboe@fb.com>
Diffstat (limited to 'block/blk-throttle.c')
-rw-r--r-- | block/blk-throttle.c | 41 |
1 files changed, 29 insertions, 12 deletions
diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 1f8d62f5e808..f6a9f42a0ad7 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c | |||
@@ -27,6 +27,8 @@ static int throtl_quantum = 32; | |||
27 | #define MAX_IDLE_TIME (5L * 1000 * 1000) /* 5 s */ | 27 | #define MAX_IDLE_TIME (5L * 1000 * 1000) /* 5 s */ |
28 | /* default latency target is 0, eg, guarantee IO latency by default */ | 28 | /* default latency target is 0, eg, guarantee IO latency by default */ |
29 | #define DFL_LATENCY_TARGET (0) | 29 | #define DFL_LATENCY_TARGET (0) |
30 | #define MIN_THROTL_BPS (320 * 1024) | ||
31 | #define MIN_THROTL_IOPS (10) | ||
30 | 32 | ||
31 | #define SKIP_LATENCY (((u64)1) << BLK_STAT_RES_SHIFT) | 33 | #define SKIP_LATENCY (((u64)1) << BLK_STAT_RES_SHIFT) |
32 | 34 | ||
@@ -296,8 +298,14 @@ static uint64_t tg_bps_limit(struct throtl_grp *tg, int rw) | |||
296 | 298 | ||
297 | td = tg->td; | 299 | td = tg->td; |
298 | ret = tg->bps[rw][td->limit_index]; | 300 | ret = tg->bps[rw][td->limit_index]; |
299 | if (ret == 0 && td->limit_index == LIMIT_LOW) | 301 | if (ret == 0 && td->limit_index == LIMIT_LOW) { |
300 | return tg->bps[rw][LIMIT_MAX]; | 302 | /* intermediate node or iops isn't 0 */ |
303 | if (!list_empty(&blkg->blkcg->css.children) || | ||
304 | tg->iops[rw][td->limit_index]) | ||
305 | return U64_MAX; | ||
306 | else | ||
307 | return MIN_THROTL_BPS; | ||
308 | } | ||
301 | 309 | ||
302 | if (td->limit_index == LIMIT_MAX && tg->bps[rw][LIMIT_LOW] && | 310 | if (td->limit_index == LIMIT_MAX && tg->bps[rw][LIMIT_LOW] && |
303 | tg->bps[rw][LIMIT_LOW] != tg->bps[rw][LIMIT_MAX]) { | 311 | tg->bps[rw][LIMIT_LOW] != tg->bps[rw][LIMIT_MAX]) { |
@@ -317,10 +325,17 @@ static unsigned int tg_iops_limit(struct throtl_grp *tg, int rw) | |||
317 | 325 | ||
318 | if (cgroup_subsys_on_dfl(io_cgrp_subsys) && !blkg->parent) | 326 | if (cgroup_subsys_on_dfl(io_cgrp_subsys) && !blkg->parent) |
319 | return UINT_MAX; | 327 | return UINT_MAX; |
328 | |||
320 | td = tg->td; | 329 | td = tg->td; |
321 | ret = tg->iops[rw][td->limit_index]; | 330 | ret = tg->iops[rw][td->limit_index]; |
322 | if (ret == 0 && tg->td->limit_index == LIMIT_LOW) | 331 | if (ret == 0 && tg->td->limit_index == LIMIT_LOW) { |
323 | return tg->iops[rw][LIMIT_MAX]; | 332 | /* intermediate node or bps isn't 0 */ |
333 | if (!list_empty(&blkg->blkcg->css.children) || | ||
334 | tg->bps[rw][td->limit_index]) | ||
335 | return UINT_MAX; | ||
336 | else | ||
337 | return MIN_THROTL_IOPS; | ||
338 | } | ||
324 | 339 | ||
325 | if (td->limit_index == LIMIT_MAX && tg->iops[rw][LIMIT_LOW] && | 340 | if (td->limit_index == LIMIT_MAX && tg->iops[rw][LIMIT_LOW] && |
326 | tg->iops[rw][LIMIT_LOW] != tg->iops[rw][LIMIT_MAX]) { | 341 | tg->iops[rw][LIMIT_LOW] != tg->iops[rw][LIMIT_MAX]) { |
@@ -1353,7 +1368,7 @@ static int tg_print_conf_uint(struct seq_file *sf, void *v) | |||
1353 | return 0; | 1368 | return 0; |
1354 | } | 1369 | } |
1355 | 1370 | ||
1356 | static void tg_conf_updated(struct throtl_grp *tg) | 1371 | static void tg_conf_updated(struct throtl_grp *tg, bool global) |
1357 | { | 1372 | { |
1358 | struct throtl_service_queue *sq = &tg->service_queue; | 1373 | struct throtl_service_queue *sq = &tg->service_queue; |
1359 | struct cgroup_subsys_state *pos_css; | 1374 | struct cgroup_subsys_state *pos_css; |
@@ -1371,7 +1386,8 @@ static void tg_conf_updated(struct throtl_grp *tg) | |||
1371 | * restrictions in the whole hierarchy and allows them to bypass | 1386 | * restrictions in the whole hierarchy and allows them to bypass |
1372 | * blk-throttle. | 1387 | * blk-throttle. |
1373 | */ | 1388 | */ |
1374 | blkg_for_each_descendant_pre(blkg, pos_css, tg_to_blkg(tg)) { | 1389 | blkg_for_each_descendant_pre(blkg, pos_css, |
1390 | global ? tg->td->queue->root_blkg : tg_to_blkg(tg)) { | ||
1375 | struct throtl_grp *this_tg = blkg_to_tg(blkg); | 1391 | struct throtl_grp *this_tg = blkg_to_tg(blkg); |
1376 | struct throtl_grp *parent_tg; | 1392 | struct throtl_grp *parent_tg; |
1377 | 1393 | ||
@@ -1434,7 +1450,7 @@ static ssize_t tg_set_conf(struct kernfs_open_file *of, | |||
1434 | else | 1450 | else |
1435 | *(unsigned int *)((void *)tg + of_cft(of)->private) = v; | 1451 | *(unsigned int *)((void *)tg + of_cft(of)->private) = v; |
1436 | 1452 | ||
1437 | tg_conf_updated(tg); | 1453 | tg_conf_updated(tg, false); |
1438 | ret = 0; | 1454 | ret = 0; |
1439 | out_finish: | 1455 | out_finish: |
1440 | blkg_conf_finish(&ctx); | 1456 | blkg_conf_finish(&ctx); |
@@ -1522,16 +1538,16 @@ static u64 tg_prfill_limit(struct seq_file *sf, struct blkg_policy_data *pd, | |||
1522 | tg->latency_target_conf == DFL_LATENCY_TARGET))) | 1538 | tg->latency_target_conf == DFL_LATENCY_TARGET))) |
1523 | return 0; | 1539 | return 0; |
1524 | 1540 | ||
1525 | if (tg->bps_conf[READ][off] != bps_dft) | 1541 | if (tg->bps_conf[READ][off] != U64_MAX) |
1526 | snprintf(bufs[0], sizeof(bufs[0]), "%llu", | 1542 | snprintf(bufs[0], sizeof(bufs[0]), "%llu", |
1527 | tg->bps_conf[READ][off]); | 1543 | tg->bps_conf[READ][off]); |
1528 | if (tg->bps_conf[WRITE][off] != bps_dft) | 1544 | if (tg->bps_conf[WRITE][off] != U64_MAX) |
1529 | snprintf(bufs[1], sizeof(bufs[1]), "%llu", | 1545 | snprintf(bufs[1], sizeof(bufs[1]), "%llu", |
1530 | tg->bps_conf[WRITE][off]); | 1546 | tg->bps_conf[WRITE][off]); |
1531 | if (tg->iops_conf[READ][off] != iops_dft) | 1547 | if (tg->iops_conf[READ][off] != UINT_MAX) |
1532 | snprintf(bufs[2], sizeof(bufs[2]), "%u", | 1548 | snprintf(bufs[2], sizeof(bufs[2]), "%u", |
1533 | tg->iops_conf[READ][off]); | 1549 | tg->iops_conf[READ][off]); |
1534 | if (tg->iops_conf[WRITE][off] != iops_dft) | 1550 | if (tg->iops_conf[WRITE][off] != UINT_MAX) |
1535 | snprintf(bufs[3], sizeof(bufs[3]), "%u", | 1551 | snprintf(bufs[3], sizeof(bufs[3]), "%u", |
1536 | tg->iops_conf[WRITE][off]); | 1552 | tg->iops_conf[WRITE][off]); |
1537 | if (off == LIMIT_LOW) { | 1553 | if (off == LIMIT_LOW) { |
@@ -1654,7 +1670,8 @@ static ssize_t tg_set_limit(struct kernfs_open_file *of, | |||
1654 | tg->latency_target_conf = latency_time; | 1670 | tg->latency_target_conf = latency_time; |
1655 | tg->latency_target = tg->latency_target_conf; | 1671 | tg->latency_target = tg->latency_target_conf; |
1656 | } | 1672 | } |
1657 | tg_conf_updated(tg); | 1673 | tg_conf_updated(tg, index == LIMIT_LOW && |
1674 | tg->td->limit_valid[LIMIT_LOW]); | ||
1658 | ret = 0; | 1675 | ret = 0; |
1659 | out_finish: | 1676 | out_finish: |
1660 | blkg_conf_finish(&ctx); | 1677 | blkg_conf_finish(&ctx); |