Commit Graph

5 Commits

Author SHA1 Message Date
Yifan Liu
ffc142d9be hv: sched_event: Change nqueued from int8_t to int32_t
This patch changes the type of nqueued in struct sched_event from int8_t
to int32_t.

In commit d575edf79, the 1 bit flag in struct sched_event has been
changed to int8_t counter to resolve race condition. Signal_event
will decrease the counter and wait_event will increase it and loop if
the counter is greater than 0.

In most cases the uses of signal_event and wait_event are consistent,
except VCPU_EVENT_VIRTUAL_INTERRUPT. In our logic, we signal this event
whenever there is an virtual interrupt, but we wait on it only in
hlt_vmexit_handler, and we reset this event before VMEnter.

In most cases this worked fine. However it has been found that in
certain GPU stress testing scenario, the signaling of this event
happened too frequently to the point where this int8_t counter underflowed
(i.e., hit -128 and then became 127). Then in subsequent
hlt_vmexit_handler, hv waited on this event and stuck there as the
counter was too large.

This patch changes the type from int8_t to int32_t to avoid underflow.

Tracked-On: #7567
Signed-off-by: Yifan Liu <yifan1.liu@intel.com>
2022-05-25 09:37:04 +08:00
Yifan Liu
d575edf79a hv: Change sched_event structure to resolve data race in event handling
Currently the sched event handling may encounter data race problem, and
as a result some vcpus might be stalled forever.

One example can be wbinvd handling where more than 1 vcpus are doing
wbinvd concurrently. The following is a possible execution of 3 vcpus:
-------
0                            1                           2
                             req [Note: 0]
                             req bit0 set [Note: 1]
                             IPI -> 0
                             req bit2 set
                             IPI -> 2
                                                         VMExit
                                                         req bit2 cleared
                                                         wait
                                                         vcpu2 descheduled

VMExit
req bit0 cleared
wait
vcpu0 descheduled
                             signal 0
                             event0->set=true
                             wake 0

                             signal 2
                             event2->set=true [Note: 3]
                             wake 2
                                                         vcpu2 scheduled
                                                         event2->set=false
                                                         resume

                                                         req
                                                         req bit0 set
                                                         IPI -> 0
                                                         req bit1 set
                                                         IPI -> 1
                             (doesn't matter)
vcpu0 scheduled [Note: 4]
                                                         signal 0
                                                         event0->set=true
                                                         (no wake) [Note: 2]
event0->set=false                                        (the rest doesn't matter)
resume

Any VMExit
req bit0 cleared
wait
idle running

(blocked forever)

Notes:
0: req: vcpu_make_request(vcpu, ACRN_REQUEST_WAIT_WBINVD).
1: req bit: Bit in pending_req_bits. Bit0 stands for bit for vcpu0.
2: In function signal_event, At this time the event->waiting_thread
    is not NULL, so wake_thread will not execute
3: eventX: struct sched_event of vcpuX.
4: In function wait_event, the lock does not strictly cover the execution between
    schedule() and event->set=false, so other threads may kick in.
-----

As shown in above example, before the last random VMExit, vcpu0 ended up
with request bit set but event->set==false, so blocked forever.

This patch proposes to change event->set from a boolean variable to an
integer. The semantic is very similar to a semaphore. The wait_event
will add 1 to this value, and block when this value is > 0, whereas signal_event
will decrease this value by 1.

It may happen that this value was decreased to a negative number but that
is OK. As long as the wait_event and signal_event are paired and
program order is observed (that is, wait_event always happens-before signal_event
on a single vcpu), this value will eventually be 0.

Tracked-On: #6405
Signed-off-by: Yifan Liu <yifan1.liu@intel.com>
2021-08-20 08:11:40 +08:00
Liang Yi
688a41c290 hv: mod: do not use explicit arch name when including headers
Instead of "#include <x86/foo.h>", use "#include <asm/foo.h>".

In other words, we are adopting the same practice in Linux kernel.

Tracked-On: #5920
Signed-off-by: Liang Yi <yi.liang@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
2021-05-08 11:15:46 +08:00
Liang Yi
33ef656462 hv/mod-irq: use arch specific header files
Requires explicit arch path name in the include directive.

The config scripts was also updated to reflect this change.

Tracked-On: #5825
Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Jason Chen CJ <jason.cj.chen@intel.com>
2021-03-24 11:38:14 +08:00
Shuo A Liu
1f23fe3fd8 hv: sched: simple event implemention
This simple event implemention can only support exclusive waiting
at same time. It mainly used by thread who want to wait for special event
happens.
  Thread A who want to wait for some events calls
	wait_event(struct sched_event *);

  Thread B who can give the event signal calls
	signal_event(struct sched_event *);

Tracked-On: #4329
Signed-off-by: Shuo A Liu <shuo.a.liu@intel.com>
Acked-by: Eddie Dong <eddie.dong@intel.com>
2020-01-07 11:23:32 +08:00