dm: protect pthread_cond_wait() against spurious wakeups

Users of pthread_cond_wait() should take care of spurious wakeups and it
is usually used in conjunction with a predicate. Not doing so can result
in unintended behavior. For example:

virtio_net_tx_thread():
  entry -> pthread_cond_wait() -> spurious wakeup ->
  vq_clear_used_ring_flags() -> segfault (vq->used uninitialized)

tpm_crb_request_deliver():
  entry -> pthread_cond_wait() -> spurious wakeup ->
  swtpm_handle_request() called needlessly

virtio_rnd_get_entropy():
  entry -> pthread_cond_wait() -> spurious wakeup ->
  no avail ring processing ->
  virtio_rnd_notify() skips pthread_cond_signal() due to
  rnd->in_progress ->
  vq_endchains() called needlessly ->
  wait in pthread_cond_wait() indefinitely

Fix these uses of pthread_cond_wait() by using predicates.

The only use case without a clear predicate is the tx thread in
virtio-mei, because it works with two-dimensional linked lists.

v1 -> v2:
- fix bugs and comments
- reduce code redundancy

Tracked-On: #2763
Signed-off-by: Peter Fang <peter.fang@intel.com>
Reviewed-by: Shuo A Liu <shuo.a.liu@intel.com>
This commit is contained in:
Peter Fang
2019-03-17 02:36:26 -07:00
committed by wenlingz
parent e9261121b3
commit f412d52546
7 changed files with 118 additions and 72 deletions

View File

@@ -265,7 +265,12 @@ static void tpm_crb_request_deliver(void *arg)
break;
}
ret = pthread_cond_wait(&tpm_vdev->request_cond, &tpm_vdev->request_mutex);
while (!ret &&
tpm_vdev->crb_regs.regs.ctrl_start == CRB_CTRL_CMD_COMPLETED) {
ret = pthread_cond_wait(
&tpm_vdev->request_cond, &tpm_vdev->request_mutex);
}
if (ret) {
DPRINTF("ERROR: Failed to wait condition(%d)\n", ret);
break;
@@ -312,6 +317,11 @@ static void crb_reg_write(struct tpm_crb_vdev *tpm_vdev, uint64_t addr, int size
(tpm_vdev->crb_regs.regs.ctrl_sts.tpmIdle != 1) &&
(get_active_locality(tpm_vdev) == target_loc)) {
if (pthread_mutex_lock(&tpm_vdev->request_mutex)) {
DPRINTF("ERROR: Failed to acquire mutex lock\n");
break;
}
tpm_vdev->crb_regs.regs.ctrl_start = CRB_CTRL_START_CMD;
cmd_size = MIN(get_tpm_cmd_size(tpm_vdev->data_buffer),
TPM_CRB_DATA_BUFFER_SIZE);
@@ -322,11 +332,6 @@ static void crb_reg_write(struct tpm_crb_vdev *tpm_vdev, uint64_t addr, int size
tpm_vdev->cmd.out = &tpm_vdev->data_buffer[0];
tpm_vdev->cmd.out_len = TPM_CRB_DATA_BUFFER_SIZE;
if (pthread_mutex_lock(&tpm_vdev->request_mutex)) {
DPRINTF("ERROR: Failed to acquire mutex lock\n");
break;
}
if (pthread_cond_signal(&tpm_vdev->request_cond)) {
DPRINTF("ERROR: Failed to wait condition\n");
break;