Skip to content

Commit 80294c3

Browse files
Algodev-githubaxboe
authored andcommitted
block, bfq: make lookup_next_entity push up vtime on expirations
To provide a very smooth service, bfq starts to serve a bfq_queue only if the queue is 'eligible', i.e., if the same queue would have started to be served in the ideal, perfectly fair system that bfq simulates internally. This is obtained by associating each queue with a virtual start time, and by computing a special system virtual time quantity: a queue is eligible only if the system virtual time has reached the virtual start time of the queue. Finally, bfq guarantees that, when a new queue must be set in service, there is always at least one eligible entity for each active parent entity in the scheduler. To provide this guarantee, the function __bfq_lookup_next_entity pushes up, for each parent entity on which it is invoked, the system virtual time to the minimum among the virtual start times of the entities in the active tree for the parent entity (more precisely, the push up occurs if the system virtual time happens to be lower than all such virtual start times). There is however a circumstance in which __bfq_lookup_next_entity cannot push up the system virtual time for a parent entity, even if the system virtual time is lower than the virtual start times of all the child entities in the active tree. It happens if one of the child entities is in service. In fact, in such a case, there is already an eligible entity, the in-service one, even if it may not be not present in the active tree (because in-service entities may be removed from the active tree). Unfortunately, in the last re-design of the hierarchical-scheduling engine, the reset of the pointer to the in-service entity for a given parent entity--reset to be done as a consequence of the expiration of the in-service entity--always happens after the function __bfq_lookup_next_entity has been invoked. This causes the function to think that there is still an entity in service for the parent entity, and then that the system virtual time cannot be pushed up, even if actually such a no-more-in-service entity has already been properly reinserted into the active tree (or in some other tree if no more active). Yet, the system virtual time *had* to be pushed up, to be ready to correctly choose the next queue to serve. Because of the lack of this push up, bfq may wrongly set in service a queue that had been speculatively pre-computed as the possible next-in-service queue, but that would no more be the one to serve after the expiration and the reinsertion into the active trees of the previously in-service entities. This commit addresses this issue by making __bfq_lookup_next_entity properly push up the system virtual time if an expiration is occurring. Signed-off-by: Paolo Valente <[email protected]> Tested-by: Lee Tibbert <[email protected]> Tested-by: Oleksandr Natalenko <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent 2b76da9 commit 80294c3

File tree

3 files changed

+47
-19
lines changed

3 files changed

+47
-19
lines changed

block/bfq-iosched.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ static void bfq_updated_next_req(struct bfq_data *bfqd,
720720
entity->budget = new_budget;
721721
bfq_log_bfqq(bfqd, bfqq, "updated next rq: new budget %lu",
722722
new_budget);
723-
bfq_requeue_bfqq(bfqd, bfqq);
723+
bfq_requeue_bfqq(bfqd, bfqq, false);
724724
}
725725
}
726726

@@ -2563,7 +2563,7 @@ static void __bfq_bfqq_expire(struct bfq_data *bfqd, struct bfq_queue *bfqq)
25632563

25642564
bfq_del_bfqq_busy(bfqd, bfqq, true);
25652565
} else {
2566-
bfq_requeue_bfqq(bfqd, bfqq);
2566+
bfq_requeue_bfqq(bfqd, bfqq, true);
25672567
/*
25682568
* Resort priority tree of potential close cooperators.
25692569
*/

block/bfq-iosched.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -817,7 +817,6 @@ extern const int bfq_timeout;
817817
struct bfq_queue *bic_to_bfqq(struct bfq_io_cq *bic, bool is_sync);
818818
void bic_set_bfqq(struct bfq_io_cq *bic, struct bfq_queue *bfqq, bool is_sync);
819819
struct bfq_data *bic_to_bfqd(struct bfq_io_cq *bic);
820-
void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq);
821820
void bfq_pos_tree_add_move(struct bfq_data *bfqd, struct bfq_queue *bfqq);
822821
void bfq_weights_tree_add(struct bfq_data *bfqd, struct bfq_entity *entity,
823822
struct rb_root *root);
@@ -917,7 +916,8 @@ void __bfq_bfqd_reset_in_service(struct bfq_data *bfqd);
917916
void bfq_deactivate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
918917
bool ins_into_idle_tree, bool expiration);
919918
void bfq_activate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq);
920-
void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq);
919+
void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
920+
bool expiration);
921921
void bfq_del_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq,
922922
bool expiration);
923923
void bfq_add_bfqq_busy(struct bfq_data *bfqd, struct bfq_queue *bfqq);

block/bfq-wf2q.c

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ static unsigned int bfq_class_idx(struct bfq_entity *entity)
4444
BFQ_DEFAULT_GRP_CLASS - 1;
4545
}
4646

47-
static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd);
47+
static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
48+
bool expiration);
4849

4950
static bool bfq_update_parent_budget(struct bfq_entity *next_in_service);
5051

@@ -54,6 +55,8 @@ static bool bfq_update_parent_budget(struct bfq_entity *next_in_service);
5455
* @new_entity: if not NULL, pointer to the entity whose activation,
5556
* requeueing or repositionig triggered the invocation of
5657
* this function.
58+
* @expiration: id true, this function is being invoked after the
59+
* expiration of the in-service entity
5760
*
5861
* This function is called to update sd->next_in_service, which, in
5962
* its turn, may change as a consequence of the insertion or
@@ -72,7 +75,8 @@ static bool bfq_update_parent_budget(struct bfq_entity *next_in_service);
7275
* entity.
7376
*/
7477
static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
75-
struct bfq_entity *new_entity)
78+
struct bfq_entity *new_entity,
79+
bool expiration)
7680
{
7781
struct bfq_entity *next_in_service = sd->next_in_service;
7882
bool parent_sched_may_change = false;
@@ -130,7 +134,7 @@ static bool bfq_update_next_in_service(struct bfq_sched_data *sd,
130134
if (replace_next)
131135
next_in_service = new_entity;
132136
} else /* invoked because of a deactivation: lookup needed */
133-
next_in_service = bfq_lookup_next_entity(sd);
137+
next_in_service = bfq_lookup_next_entity(sd, expiration);
134138

135139
if (next_in_service) {
136140
parent_sched_may_change = !sd->next_in_service ||
@@ -1127,18 +1131,21 @@ static void __bfq_activate_requeue_entity(struct bfq_entity *entity,
11271131
* @requeue: true if this is a requeue, which implies that bfqq is
11281132
* being expired; thus ALL its ancestors stop being served and must
11291133
* therefore be requeued
1134+
* @expiration: true if this function is being invoked in the expiration path
1135+
* of the in-service queue
11301136
*/
11311137
static void bfq_activate_requeue_entity(struct bfq_entity *entity,
11321138
bool non_blocking_wait_rq,
1133-
bool requeue)
1139+
bool requeue, bool expiration)
11341140
{
11351141
struct bfq_sched_data *sd;
11361142

11371143
for_each_entity(entity) {
11381144
sd = entity->sched_data;
11391145
__bfq_activate_requeue_entity(entity, sd, non_blocking_wait_rq);
11401146

1141-
if (!bfq_update_next_in_service(sd, entity) && !requeue)
1147+
if (!bfq_update_next_in_service(sd, entity, expiration) &&
1148+
!requeue)
11421149
break;
11431150
}
11441151
}
@@ -1194,6 +1201,8 @@ bool __bfq_deactivate_entity(struct bfq_entity *entity, bool ins_into_idle_tree)
11941201
* bfq_deactivate_entity - deactivate an entity representing a bfq_queue.
11951202
* @entity: the entity to deactivate.
11961203
* @ins_into_idle_tree: true if the entity can be put into the idle tree
1204+
* @expiration: true if this function is being invoked in the expiration path
1205+
* of the in-service queue
11971206
*/
11981207
static void bfq_deactivate_entity(struct bfq_entity *entity,
11991208
bool ins_into_idle_tree,
@@ -1222,7 +1231,7 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
12221231
* then, since entity has just been
12231232
* deactivated, a new one must be found.
12241233
*/
1225-
bfq_update_next_in_service(sd, NULL);
1234+
bfq_update_next_in_service(sd, NULL, expiration);
12261235

12271236
if (sd->next_in_service || sd->in_service_entity) {
12281237
/*
@@ -1281,7 +1290,7 @@ static void bfq_deactivate_entity(struct bfq_entity *entity,
12811290
__bfq_requeue_entity(entity);
12821291

12831292
sd = entity->sched_data;
1284-
if (!bfq_update_next_in_service(sd, entity) &&
1293+
if (!bfq_update_next_in_service(sd, entity, expiration) &&
12851294
!expiration)
12861295
/*
12871296
* next_in_service unchanged or not causing
@@ -1416,12 +1425,14 @@ __bfq_lookup_next_entity(struct bfq_service_tree *st, bool in_service)
14161425
/**
14171426
* bfq_lookup_next_entity - return the first eligible entity in @sd.
14181427
* @sd: the sched_data.
1428+
* @expiration: true if we are on the expiration path of the in-service queue
14191429
*
14201430
* This function is invoked when there has been a change in the trees
1421-
* for sd, and we need know what is the new next entity after this
1422-
* change.
1431+
* for sd, and we need to know what is the new next entity to serve
1432+
* after this change.
14231433
*/
1424-
static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd)
1434+
static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd,
1435+
bool expiration)
14251436
{
14261437
struct bfq_service_tree *st = sd->service_tree;
14271438
struct bfq_service_tree *idle_class_st = st + (BFQ_IOPRIO_CLASSES - 1);
@@ -1448,8 +1459,24 @@ static struct bfq_entity *bfq_lookup_next_entity(struct bfq_sched_data *sd)
14481459
* class, unless the idle class needs to be served.
14491460
*/
14501461
for (; class_idx < BFQ_IOPRIO_CLASSES; class_idx++) {
1462+
/*
1463+
* If expiration is true, then bfq_lookup_next_entity
1464+
* is being invoked as a part of the expiration path
1465+
* of the in-service queue. In this case, even if
1466+
* sd->in_service_entity is not NULL,
1467+
* sd->in_service_entiy at this point is actually not
1468+
* in service any more, and, if needed, has already
1469+
* been properly queued or requeued into the right
1470+
* tree. The reason why sd->in_service_entity is still
1471+
* not NULL here, even if expiration is true, is that
1472+
* sd->in_service_entiy is reset as a last step in the
1473+
* expiration path. So, if expiration is true, tell
1474+
* __bfq_lookup_next_entity that there is no
1475+
* sd->in_service_entity.
1476+
*/
14511477
entity = __bfq_lookup_next_entity(st + class_idx,
1452-
sd->in_service_entity);
1478+
sd->in_service_entity &&
1479+
!expiration);
14531480

14541481
if (entity)
14551482
break;
@@ -1562,7 +1589,7 @@ struct bfq_queue *bfq_get_next_queue(struct bfq_data *bfqd)
15621589
for_each_entity(entity) {
15631590
struct bfq_sched_data *sd = entity->sched_data;
15641591

1565-
if (!bfq_update_next_in_service(sd, NULL))
1592+
if (!bfq_update_next_in_service(sd, NULL, false))
15661593
break;
15671594
}
15681595

@@ -1610,16 +1637,17 @@ void bfq_activate_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq)
16101637
struct bfq_entity *entity = &bfqq->entity;
16111638

16121639
bfq_activate_requeue_entity(entity, bfq_bfqq_non_blocking_wait_rq(bfqq),
1613-
false);
1640+
false, false);
16141641
bfq_clear_bfqq_non_blocking_wait_rq(bfqq);
16151642
}
16161643

1617-
void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq)
1644+
void bfq_requeue_bfqq(struct bfq_data *bfqd, struct bfq_queue *bfqq,
1645+
bool expiration)
16181646
{
16191647
struct bfq_entity *entity = &bfqq->entity;
16201648

16211649
bfq_activate_requeue_entity(entity, false,
1622-
bfqq == bfqd->in_service_queue);
1650+
bfqq == bfqd->in_service_queue, expiration);
16231651
}
16241652

16251653
/*

0 commit comments

Comments
 (0)