* [Qemu-devel] [PATCH v2 0/3] TPM NVRAM persistent storage
@ 2013-06-05 20:47 Corey Bryant
2013-06-05 20:47 ` [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation Corey Bryant
2013-06-05 20:48 ` [Qemu-devel] [PATCH v2 2/3] nvram: Add tpm-tis drive support Corey Bryant
0 siblings, 2 replies; 5+ messages in thread
From: Corey Bryant @ 2013-06-05 20:47 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, aliguori, stefanb, Corey Bryant, mdroth, jschopp, stefanha
This patch series provides persistent storage support that a TPM
can use to store NVRAM data. It uses QEMU's block driver to store
data on a drive image. The libtpms TPM 1.2 backend will be the
initial user of this functionality to store data that must persist
through a reboot or migration. A sample command line may look like
this:
qemu-system-x86_64 ...
-drive file=/path/to/nvram.qcow2,id=drive-nvram0-0-0
-tpmdev libtpms,id=tpm-tpm0
-device tpm-tis,tpmdev=tpm-tpm0,id=tpm0,drive=drive-nvram0-0-0
Thanks,
Corey
Corey Bryant (3):
nvram: Add TPM NVRAM implementation
nvram: Add tpm-tis drive support
TPM NVRAM test
hw/tpm/Makefile.objs | 1 +
hw/tpm/tpm_int.h | 2 +
hw/tpm/tpm_nvram.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_nvram.h | 25 ++++
hw/tpm/tpm_passthrough.c | 85 ++++++++++++
hw/tpm/tpm_tis.c | 8 +
6 files changed, 447 insertions(+), 0 deletions(-)
create mode 100644 hw/tpm/tpm_nvram.c
create mode 100644 hw/tpm/tpm_nvram.h
^ permalink raw reply [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation
2013-06-05 20:47 [Qemu-devel] [PATCH v2 0/3] TPM NVRAM persistent storage Corey Bryant
@ 2013-06-05 20:47 ` Corey Bryant
2013-06-06 9:22 ` Stefan Hajnoczi
2013-06-05 20:48 ` [Qemu-devel] [PATCH v2 2/3] nvram: Add tpm-tis drive support Corey Bryant
1 sibling, 1 reply; 5+ messages in thread
From: Corey Bryant @ 2013-06-05 20:47 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, aliguori, stefanb, Corey Bryant, mdroth, jschopp, stefanha
Provides TPM NVRAM implementation that enables storing of TPM
NVRAM data in a persistent image file. The block driver is
used to read/write the drive image. This will enable, for
example, an encrypted QCOW2 image to be used to store sensitive
keys.
This patch provides APIs that a TPM backend can use to read and
write data.
Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
---
v2
-Use non bit-rotting DPRINTF (stefanha@redhat.com)
-Use DIV_ROUND_UP (stefanha@redhat.com)
-Use bdrv_pread/bdrv_pwrite in coroutine - causes global
sector to byte I/O changes (stefanha@redhat.com, kwolf@redhat.com)
-Add tpm_nvram_required_size_kb() and update tpm_nvram_adjust_size()
-Drop qemu_aio_wait() from tpm_nvram_do_co_read/write() and move
any completion code path to coroutines
-Replace tpm_nvram_rwrequest_free() with g_free(rwr)
-Remove unneeded arg checks from tpm_nvram_read/write()
(stefanha@redhat.com)
-Init rwr->rc to -EINPROGRESS and wrap qemu_cond_wait() with check
(stefanha@redhat.com)
-Add init of completion_mutex and completion condition
---
hw/tpm/Makefile.objs | 1 +
hw/tpm/tpm_nvram.c | 326 ++++++++++++++++++++++++++++++++++++++++++++++++++
hw/tpm/tpm_nvram.h | 25 ++++
3 files changed, 352 insertions(+), 0 deletions(-)
create mode 100644 hw/tpm/tpm_nvram.c
create mode 100644 hw/tpm/tpm_nvram.h
diff --git a/hw/tpm/Makefile.objs b/hw/tpm/Makefile.objs
index 99f5983..49faef4 100644
--- a/hw/tpm/Makefile.objs
+++ b/hw/tpm/Makefile.objs
@@ -1,2 +1,3 @@
common-obj-$(CONFIG_TPM_TIS) += tpm_tis.o
+common-obj-$(CONFIG_TPM_TIS) += tpm_nvram.o
common-obj-$(CONFIG_TPM_PASSTHROUGH) += tpm_passthrough.o
diff --git a/hw/tpm/tpm_nvram.c b/hw/tpm/tpm_nvram.c
new file mode 100644
index 0000000..01f0dee
--- /dev/null
+++ b/hw/tpm/tpm_nvram.c
@@ -0,0 +1,326 @@
+/*
+ * TPM NVRAM - enables storage of persistent NVRAM data on an image file
+ *
+ * Copyright (C) 2013 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ * Corey Bryant <coreyb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#include "tpm_nvram.h"
+#include "block/block_int.h"
+#include "qemu/thread.h"
+#include "sysemu/sysemu.h"
+
+#define TPM_NVRAM_DEBUG 0
+#define DPRINTF(fmt, ...) \
+ do { \
+ if (TPM_NVRAM_DEBUG) { \
+ fprintf(stderr, fmt, ## __VA_ARGS__); \
+ } \
+ } while (0)
+
+/* Read/write request data */
+typedef struct TPMNvramRWRequest {
+ BlockDriverState *bdrv;
+ bool is_write;
+ uint64_t offset;
+ uint8_t **blob_r;
+ uint8_t *blob_w;
+ uint32_t size;
+ int rc;
+
+ QemuMutex completion_mutex;
+ QemuCond completion;
+
+ QSIMPLEQ_ENTRY(TPMNvramRWRequest) list;
+} TPMNvramRWRequest;
+
+/* Mutex protected queue of read/write requests */
+static QemuMutex tpm_nvram_rwrequests_mutex;
+static QSIMPLEQ_HEAD(, TPMNvramRWRequest) tpm_nvram_rwrequests =
+ QSIMPLEQ_HEAD_INITIALIZER(tpm_nvram_rwrequests);
+
+static QEMUBH *tpm_nvram_bh;
+
+/*
+ * Get the disk size in kilobytes needed to store a blob (rounded up to next kb)
+ */
+static uint64_t tpm_nvram_required_size_kb(uint64_t offset, uint32_t size)
+{
+ uint64_t required_size = offset + size;
+ return DIV_ROUND_UP(required_size, 1024);
+}
+
+/*
+ * Increase the drive size if it's too small to store the blob
+ */
+static int tpm_nvram_adjust_size(BlockDriverState *bdrv, uint64_t offset,
+ uint32_t size)
+{
+ int rc = 0;
+ int64_t drive_size, required_size;
+
+ rc = bdrv_getlength(bdrv);
+ if (rc < 0) {
+ DPRINTF("%s: Unable to determine TPM NVRAM drive size\n", __func__);
+ return rc;
+ }
+
+ drive_size = rc;
+ required_size = tpm_nvram_required_size_kb(offset, size) * 1024;
+
+ if (drive_size < required_size) {
+ rc = bdrv_truncate(bdrv, required_size);
+ if (rc < 0) {
+ DPRINTF("%s: TPM NVRAM drive too small\n", __func__);
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Coroutine that reads a blob from the drive asynchronously
+ */
+static void coroutine_fn tpm_nvram_co_read(void *opaque)
+{
+ TPMNvramRWRequest *rwr = opaque;
+
+ *rwr->blob_r = g_malloc(rwr->size);
+
+ rwr->rc = bdrv_pread(rwr->bdrv,
+ rwr->offset,
+ *rwr->blob_r,
+ rwr->size);
+ if (rwr->rc != rwr->size) {
+ g_free(*rwr->blob_r);
+ *rwr->blob_r = NULL;
+ }
+
+ qemu_mutex_lock(&rwr->completion_mutex);
+ qemu_cond_signal(&rwr->completion);
+ qemu_mutex_unlock(&rwr->completion_mutex);
+}
+
+/*
+ * Coroutine that writes a blob to the drive asynchronously
+ */
+static void coroutine_fn tpm_nvram_co_write(void *opaque)
+{
+ TPMNvramRWRequest *rwr = opaque;
+
+ rwr->rc = bdrv_pwrite(rwr->bdrv,
+ rwr->offset,
+ rwr->blob_w,
+ rwr->size);
+
+ qemu_mutex_lock(&rwr->completion_mutex);
+ qemu_cond_signal(&rwr->completion);
+ qemu_mutex_unlock(&rwr->completion_mutex);
+}
+
+/*
+ * Enter a coroutine to read a blob from the drive
+ */
+static void tpm_nvram_do_co_read(TPMNvramRWRequest *rwr)
+{
+ Coroutine *co;
+
+ co = qemu_coroutine_create(tpm_nvram_co_read);
+ qemu_coroutine_enter(co, rwr);
+}
+
+/*
+ * Enter a coroutine to write a blob to the drive
+ */
+static void tpm_nvram_do_co_write(TPMNvramRWRequest *rwr)
+{
+ int rc;
+ Coroutine *co;
+
+ rc = tpm_nvram_adjust_size(rwr->bdrv, rwr->offset, rwr->size);
+ if (rc < 0) {
+ rwr->rc = rc;
+ return;
+ }
+
+ co = qemu_coroutine_create(tpm_nvram_co_write);
+ qemu_coroutine_enter(co, rwr);
+}
+
+/*
+ * Initialization for read requests
+ */
+static TPMNvramRWRequest *tpm_nvram_rwrequest_init_read(BlockDriverState *bdrv,
+ uint64_t offset,
+ uint8_t **blob,
+ uint32_t size)
+{
+ TPMNvramRWRequest *rwr;
+
+ rwr = g_new0(TPMNvramRWRequest, 1);
+ rwr->bdrv = bdrv;
+ rwr->is_write = false;
+ rwr->offset = offset;
+ rwr->blob_r = blob;
+ rwr->size = size;
+ rwr->rc = -EINPROGRESS;
+
+ qemu_mutex_init(&rwr->completion_mutex);
+ qemu_cond_init(&rwr->completion);
+
+ return rwr;
+}
+
+/*
+ * Initialization for write requests
+ */
+static TPMNvramRWRequest *tpm_nvram_rwrequest_init_write(BlockDriverState *bdrv,
+ uint64_t offset,
+ uint8_t *blob,
+ uint32_t size)
+{
+ TPMNvramRWRequest *rwr;
+
+ rwr = g_new0(TPMNvramRWRequest, 1);
+ rwr->bdrv = bdrv;
+ rwr->is_write = true;
+ rwr->offset = offset;
+ rwr->blob_w = blob;
+ rwr->size = size;
+ rwr->rc = -EINPROGRESS;
+
+ qemu_mutex_init(&rwr->completion_mutex);
+ qemu_cond_init(&rwr->completion);
+
+ return rwr;
+}
+
+/*
+ * Execute a read or write of TPM NVRAM blob data
+ */
+static void tpm_nvram_rwrequest_exec(TPMNvramRWRequest *rwr)
+{
+ if (rwr->is_write) {
+ tpm_nvram_do_co_write(rwr);
+ } else {
+ tpm_nvram_do_co_read(rwr);
+ }
+}
+
+/*
+ * Bottom-half callback that is invoked by QEMU's main thread to
+ * process TPM NVRAM read/write requests.
+ */
+static void tpm_nvram_rwrequest_callback(void *opaque)
+{
+ TPMNvramRWRequest *rwr, *next;
+
+ qemu_mutex_lock(&tpm_nvram_rwrequests_mutex);
+
+ QSIMPLEQ_FOREACH_SAFE(rwr, &tpm_nvram_rwrequests, list, next) {
+ QSIMPLEQ_REMOVE(&tpm_nvram_rwrequests, rwr, TPMNvramRWRequest, list);
+
+ qemu_mutex_unlock(&tpm_nvram_rwrequests_mutex);
+ tpm_nvram_rwrequest_exec(rwr);
+ qemu_mutex_lock(&tpm_nvram_rwrequests_mutex);
+ }
+
+ qemu_mutex_unlock(&tpm_nvram_rwrequests_mutex);
+}
+
+/*
+ * Schedule a bottom-half to read or write a blob to the TPM NVRAM drive
+ */
+static void tpm_nvram_rwrequest_schedule(TPMNvramRWRequest *rwr)
+{
+ qemu_mutex_lock(&tpm_nvram_rwrequests_mutex);
+ QSIMPLEQ_INSERT_TAIL(&tpm_nvram_rwrequests, rwr, list);
+ qemu_mutex_unlock(&tpm_nvram_rwrequests_mutex);
+
+ qemu_bh_schedule(tpm_nvram_bh);
+
+ /* Wait for completion of the read/write request */
+ qemu_mutex_lock(&rwr->completion_mutex);
+ while (rwr->rc == -EINPROGRESS) {
+ qemu_cond_wait(&rwr->completion, &rwr->completion_mutex);
+ }
+ qemu_mutex_unlock(&rwr->completion_mutex);
+}
+
+/*
+ * Initialize a TPM NVRAM drive
+ */
+int tpm_nvram_init(BlockDriverState *bdrv)
+{
+ qemu_mutex_init(&tpm_nvram_rwrequests_mutex);
+ tpm_nvram_bh = qemu_bh_new(tpm_nvram_rwrequest_callback, NULL);
+
+ if (bdrv_is_read_only(bdrv)) {
+ DPRINTF("%s: TPM NVRAM drive '%s' is read-only\n", __func__,
+ bdrv->filename);
+ return -EPERM;
+ }
+
+ bdrv_lock_medium(bdrv, true);
+
+ DPRINTF("%s: TPM NVRAM drive '%s' initialized successfully\n", __func__,
+ bdrv->filename);
+
+ return 0;
+}
+
+/*
+ * Read a TPM NVRAM blob from the drive
+ */
+int tpm_nvram_read(BlockDriverState *bdrv, uint64_t offset,
+ uint8_t **blob, uint32_t size)
+{
+ int rc;
+ TPMNvramRWRequest *rwr;
+
+ *blob = NULL;
+
+ rwr = tpm_nvram_rwrequest_init_read(bdrv, offset, blob, size);
+ tpm_nvram_rwrequest_schedule(rwr);
+ rc = rwr->rc;
+
+ if (rc != rwr->size) {
+ DPRINTF("%s: TPM NVRAM read failed\n", __func__);
+ } else {
+ DPRINTF("%s: TPM NVRAM read successful: offset=%"PRIu64", "
+ "size=%"PRIu32"\n", __func__, rwr->offset, rwr->size);
+ }
+
+ g_free(rwr);
+ return rc;
+}
+
+/*
+ * Write a TPM NVRAM blob to the drive
+ */
+int tpm_nvram_write(BlockDriverState *bdrv, uint64_t offset,
+ uint8_t *blob, uint32_t size)
+{
+ int rc;
+ TPMNvramRWRequest *rwr;
+
+ rwr = tpm_nvram_rwrequest_init_write(bdrv, offset, blob, size);
+ tpm_nvram_rwrequest_schedule(rwr);
+ rc = rwr->rc;
+
+ if (rc != rwr->size) {
+ DPRINTF("%s: TPM NVRAM write failed\n", __func__);
+ } else {
+ DPRINTF("%s: TPM NVRAM write successful: offset=%"PRIu64", "
+ "size=%"PRIu32"\n", __func__, rwr->offset, rwr->size);
+ }
+
+ g_free(rwr);
+ return rc;
+}
diff --git a/hw/tpm/tpm_nvram.h b/hw/tpm/tpm_nvram.h
new file mode 100644
index 0000000..4b5bbe0
--- /dev/null
+++ b/hw/tpm/tpm_nvram.h
@@ -0,0 +1,25 @@
+/*
+ * TPM NVRAM - enables storage of persistent NVRAM data on an image file
+ *
+ * Copyright (C) 2013 IBM Corporation
+ *
+ * Authors:
+ * Stefan Berger <stefanb@us.ibm.com>
+ * Corey Bryant <coreyb@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef TPM_TPM_NVRAM_H
+#define TPM_TPM_NVRAM_H
+
+#include "block/block.h"
+
+int tpm_nvram_init(BlockDriverState *bdrv);
+int tpm_nvram_read(BlockDriverState *bdrv, uint64_t offset,
+ uint8_t **blob, uint32_t size);
+int tpm_nvram_write(BlockDriverState *bdrv, uint64_t offset,
+ uint8_t *blob, uint32_t size);
+
+#endif
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [Qemu-devel] [PATCH v2 2/3] nvram: Add tpm-tis drive support
2013-06-05 20:47 [Qemu-devel] [PATCH v2 0/3] TPM NVRAM persistent storage Corey Bryant
2013-06-05 20:47 ` [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation Corey Bryant
@ 2013-06-05 20:48 ` Corey Bryant
1 sibling, 0 replies; 5+ messages in thread
From: Corey Bryant @ 2013-06-05 20:48 UTC (permalink / raw)
To: qemu-devel
Cc: kwolf, aliguori, stefanb, Corey Bryant, mdroth, jschopp, stefanha
Add a drive property to the tpm-tis device and initialize the TPM
NVRAM if a drive is specified.
Signed-off-by: Corey Bryant <coreyb@linux.vnet.ibm.com>
---
v2
-No changes
---
hw/tpm/tpm_int.h | 2 ++
hw/tpm/tpm_tis.c | 8 ++++++++
2 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 2f582ca..05471ef 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -29,6 +29,8 @@ struct TPMState {
char *backend;
TPMBackend *be_driver;
+
+ BlockDriverState *bdrv;
};
#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index d4d8152..8648b3b 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -27,6 +27,7 @@
#include "hw/i386/pc.h"
#include "hw/pci/pci_ids.h"
#include "tpm_tis.h"
+#include "tpm_nvram.h"
#include "qemu-common.h"
/*#define DEBUG_TIS */
@@ -849,6 +850,7 @@ static Property tpm_tis_properties[] = {
DEFINE_PROP_UINT32("irq", TPMState,
s.tis.irq_num, TPM_TIS_IRQ),
DEFINE_PROP_STRING("tpmdev", TPMState, backend),
+ DEFINE_PROP_DRIVE("drive", TPMState, bdrv),
DEFINE_PROP_END_OF_LIST(),
};
@@ -864,6 +866,12 @@ static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
return;
}
+ if (s->bdrv && tpm_nvram_init(s->bdrv)) {
+ error_setg(errp, "tpm_tis: backend drive with id %s could not "
+ "initialize TPM NVRAM drive", s->backend);
+ return;
+ }
+
s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
--
1.7.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation
2013-06-05 20:47 ` [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation Corey Bryant
@ 2013-06-06 9:22 ` Stefan Hajnoczi
2013-06-06 13:32 ` Corey Bryant
0 siblings, 1 reply; 5+ messages in thread
From: Stefan Hajnoczi @ 2013-06-06 9:22 UTC (permalink / raw)
To: Corey Bryant
Cc: kwolf, aliguori, stefanb, mdroth, qemu-devel, jschopp, stefanha
On Wed, Jun 05, 2013 at 04:47:59PM -0400, Corey Bryant wrote:
> +/*
> + * Coroutine that reads a blob from the drive asynchronously
> + */
> +static void coroutine_fn tpm_nvram_co_read(void *opaque)
> +{
> + TPMNvramRWRequest *rwr = opaque;
> +
> + *rwr->blob_r = g_malloc(rwr->size);
> +
> + rwr->rc = bdrv_pread(rwr->bdrv,
> + rwr->offset,
> + *rwr->blob_r,
> + rwr->size);
> + if (rwr->rc != rwr->size) {
> + g_free(*rwr->blob_r);
> + *rwr->blob_r = NULL;
> + }
> +
> + qemu_mutex_lock(&rwr->completion_mutex);
Race condition: we must only store rwr->rc while holding
->completion_mutex. Otherwise the other thread may see ->rc and
g_free(rwr) before we leave this function, causing us to operate on
freed memory.
I suggest storing rc into a local variable first and then assigning to
rwr->rc here.
> +/*
> + * Enter a coroutine to write a blob to the drive
> + */
> +static void tpm_nvram_do_co_write(TPMNvramRWRequest *rwr)
> +{
> + int rc;
> + Coroutine *co;
> +
> + rc = tpm_nvram_adjust_size(rwr->bdrv, rwr->offset, rwr->size);
> + if (rc < 0) {
> + rwr->rc = rc;
> + return;
> + }
Do this inside the tpm_nvram_co_write() coroutine so error return still
signals the condvar. Right now the other thread may miss completion and
deadlock.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation
2013-06-06 9:22 ` Stefan Hajnoczi
@ 2013-06-06 13:32 ` Corey Bryant
0 siblings, 0 replies; 5+ messages in thread
From: Corey Bryant @ 2013-06-06 13:32 UTC (permalink / raw)
To: Stefan Hajnoczi
Cc: kwolf, aliguori, stefanb, qemu-devel, mdroth, jschopp, stefanha
On 06/06/2013 05:22 AM, Stefan Hajnoczi wrote:
> On Wed, Jun 05, 2013 at 04:47:59PM -0400, Corey Bryant wrote:
>> +/*
>> + * Coroutine that reads a blob from the drive asynchronously
>> + */
>> +static void coroutine_fn tpm_nvram_co_read(void *opaque)
>> +{
>> + TPMNvramRWRequest *rwr = opaque;
>> +
>> + *rwr->blob_r = g_malloc(rwr->size);
>> +
>> + rwr->rc = bdrv_pread(rwr->bdrv,
>> + rwr->offset,
>> + *rwr->blob_r,
>> + rwr->size);
>> + if (rwr->rc != rwr->size) {
>> + g_free(*rwr->blob_r);
>> + *rwr->blob_r = NULL;
>> + }
>> +
>> + qemu_mutex_lock(&rwr->completion_mutex);
>
> Race condition: we must only store rwr->rc while holding
> ->completion_mutex. Otherwise the other thread may see ->rc and
> g_free(rwr) before we leave this function, causing us to operate on
> freed memory.
>
> I suggest storing rc into a local variable first and then assigning to
> rwr->rc here.
>
>> +/*
>> + * Enter a coroutine to write a blob to the drive
>> + */
>> +static void tpm_nvram_do_co_write(TPMNvramRWRequest *rwr)
>> +{
>> + int rc;
>> + Coroutine *co;
>> +
>> + rc = tpm_nvram_adjust_size(rwr->bdrv, rwr->offset, rwr->size);
>> + if (rc < 0) {
>> + rwr->rc = rc;
>> + return;
>> + }
>
> Do this inside the tpm_nvram_co_write() coroutine so error return still
> signals the condvar. Right now the other thread may miss completion and
> deadlock.
>
>
Thanks for the review. Sending a v3 out to the list now.
--
Regards,
Corey Bryant
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2013-06-06 13:33 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-06-05 20:47 [Qemu-devel] [PATCH v2 0/3] TPM NVRAM persistent storage Corey Bryant
2013-06-05 20:47 ` [Qemu-devel] [PATCH v2 1/3] nvram: Add TPM NVRAM implementation Corey Bryant
2013-06-06 9:22 ` Stefan Hajnoczi
2013-06-06 13:32 ` Corey Bryant
2013-06-05 20:48 ` [Qemu-devel] [PATCH v2 2/3] nvram: Add tpm-tis drive support Corey Bryant
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.