hv: sched: fix bug when reboot vm

BVT schedule rule:
When a new thread is wakeup and added to runqueue, it will get the
smallest avt (svt) from runqueue to initiate its avt. If the svt is
small than it's avt, it will keep the original avt.

For the reboot issue, when the VM is reboot, it means a new vcpu thread
is wakeup, but at this time, the Service VM's vcpu thread is blocked,
and removed from the runqueue, and the runqueue is empty, so the svt is
0. The new vcpu thread will get avt=0. avt=0 means very high priority,
and can run for a very long time until it catchup with other thread's
avt in runqueue.
At this time, when Service VM's vcpu thread wakeup, it will check the
svt, but the svt is very small, so will not update it's avt according to
the rule, thus has a very low priority and cannot be scheduled.

To fix it, adjust the new thread's avt when there is another thread in
runqueue.

Tracked-On: #7692
Signed-off-by: Conghui <conghui.chen@intel.com>
This commit is contained in:
Conghui 2021-11-23 16:11:02 +08:00 committed by acrnsi-robot
parent 6589d0c337
commit 8c13ff78f9

View File

@ -28,6 +28,7 @@ struct sched_bvt_data {
/* effective virtual time in units of mcu */
int64_t evt;
uint64_t residual;
bool unlimit;
uint64_t start_tsc;
};
@ -185,6 +186,7 @@ static void sched_bvt_init_data(struct thread_object *obj)
/* TODO: virtual time advance ratio should be proportional to weight. */
data->vt_ratio = 1U;
data->residual = 0U;
data->unlimit = true;
data->run_countdown = BVT_CSA_MCU;
}
@ -200,12 +202,35 @@ static uint64_t p2v(uint64_t phy_time, uint64_t ratio)
static void update_vt(struct thread_object *obj)
{
struct sched_bvt_data *data;
struct sched_bvt_data *data, *sec_data;
struct list_head *first, *sec;
struct thread_object *sec_obj;
uint64_t now_tsc = cpu_ticks();
uint64_t v_delta, delta_mcu = 0U;
struct sched_bvt_control *bvt_ctl =
(struct sched_bvt_control *)obj->sched_ctl->priv;
data = (struct sched_bvt_data *)obj->data;
/*if this thread is new, need to adjuest its avt refer to other old thread*/
if (data->unlimit) {
if (is_inqueue(obj)) {
first = bvt_ctl->runqueue.next;
sec = (first->next == &bvt_ctl->runqueue) ? NULL : first->next;
if (sec != NULL) {
sec_obj = container_of(sec, struct thread_object, data);
sec_data = (struct sched_bvt_data *)sec_obj->data;
if (sec_data->avt !=0) {
data->avt = sec_data->avt;
data->unlimit = false;
pr_dbg("update: unlimit turn-off, new avt = %d", data->avt);
}
}
} else {
if (!list_empty(&bvt_ctl->runqueue)) {
data->avt = get_svt(obj);
}
}
}
/* update current thread's avt and evt */
if (now_tsc > data->start_tsc) {
v_delta = p2v(now_tsc - data->start_tsc, data->vt_ratio) + data->residual;
@ -279,12 +304,21 @@ static void sched_bvt_wake(struct thread_object *obj)
{
struct sched_bvt_data *data;
int64_t svt, threshold;
struct sched_bvt_control *bvt_ctl =
(struct sched_bvt_control *)obj->sched_ctl->priv;
data = (struct sched_bvt_data *)obj->data;
svt = get_svt(obj);
threshold = svt - BVT_CSA_MCU;
/* adjusting AVT for a thread after a long sleep */
data->avt = (data->avt > threshold) ? data->avt : svt;
if (data->unlimit && !list_empty(&bvt_ctl->runqueue))
{
/* new thread is wakeup, and find valid avt, so turn-off unlimit */
pr_dbg("wake: unlimit turn-off");
data->unlimit = false;
}
/* TODO: evt = avt - (warp ? warpback : 0U) */
data->evt = data->avt;
/* add to runqueue in order */