|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [PATCH RFC v2 13/23] libxc/migration: add try_read_record()
From: Joshua Otto <jtotto@xxxxxxxxxxxx>
Enable non-blocking migration record reads by adding a helper routine that
manages the context of a record read across multiple invocations as the record's
data becomes available over time.
Signed-off-by: Joshua Otto <jtotto@xxxxxxxxxxxx>
---
tools/libxc/xc_private.c | 21 +++++++++++----
tools/libxc/xc_private.h | 2 ++
tools/libxc/xc_sr_common.c | 65 ++++++++++++++++++++++++++++++++++++++++++++++
tools/libxc/xc_sr_common.h | 39 ++++++++++++++++++++++++++++
4 files changed, 122 insertions(+), 5 deletions(-)
diff --git a/tools/libxc/xc_private.c b/tools/libxc/xc_private.c
index f395594..b33d02f 100644
--- a/tools/libxc/xc_private.c
+++ b/tools/libxc/xc_private.c
@@ -633,26 +633,37 @@ void bitmap_byte_to_64(uint64_t *lp, const uint8_t *bp,
int nbits)
}
}
-int read_exact(int fd, void *data, size_t size)
+int try_read_exact(int fd, void *data, size_t size, size_t *offset)
{
- size_t offset = 0;
ssize_t len;
- while ( offset < size )
+ assert(offset);
+ *offset = 0;
+ while ( *offset < size )
{
- len = read(fd, (char *)data + offset, size - offset);
+ len = read(fd, (char *)data + *offset, size - *offset);
if ( (len == -1) && (errno == EINTR) )
continue;
if ( len == 0 )
errno = 0;
if ( len <= 0 )
return -1;
- offset += len;
+ *offset += len;
}
return 0;
}
+int read_exact(int fd, void *data, size_t size)
+{
+ size_t offset;
+ int rc;
+
+ rc = try_read_exact(fd, data, size, &offset);
+ assert(rc == -1 || offset == size);
+ return rc;
+}
+
int write_exact(int fd, const void *data, size_t size)
{
size_t offset = 0;
diff --git a/tools/libxc/xc_private.h b/tools/libxc/xc_private.h
index 1c27b0f..aaae344 100644
--- a/tools/libxc/xc_private.h
+++ b/tools/libxc/xc_private.h
@@ -384,6 +384,8 @@ int xc_flush_mmu_updates(xc_interface *xch, struct xc_mmu
*mmu);
/* Return 0 on success; -1 on error setting errno. */
int read_exact(int fd, void *data, size_t size); /* EOF => -1, errno=0 */
+/* Like read_exact(), but stores the length read before error to *offset. */
+int try_read_exact(int fd, void *data, size_t size, size_t *offset);
int write_exact(int fd, const void *data, size_t size);
int writev_exact(int fd, const struct iovec *iov, int iovcnt);
diff --git a/tools/libxc/xc_sr_common.c b/tools/libxc/xc_sr_common.c
index 090b5fd..c37fe1f 100644
--- a/tools/libxc/xc_sr_common.c
+++ b/tools/libxc/xc_sr_common.c
@@ -147,6 +147,71 @@ int read_record(struct xc_sr_context *ctx, int fd, struct
xc_sr_record *rec)
return 0;
};
+int try_read_record(struct xc_sr_read_record_context *rrctx, int fd,
+ struct xc_sr_record *rec)
+{
+ int rc;
+ xc_interface *xch = rrctx->ctx->xch;
+ size_t offset_out, dataoff, datasz;
+
+ /* If the header isn't yet complete, attempt to finish it first. */
+ if ( rrctx->offset < sizeof(rrctx->rhdr) )
+ {
+ rc = try_read_exact(fd, (char *)&rrctx->rhdr + rrctx->offset,
+ sizeof(rrctx->rhdr) - rrctx->offset, &offset_out);
+ rrctx->offset += offset_out;
+
+ if ( rc )
+ return rc;
+ }
+
+ datasz = ROUNDUP(rrctx->rhdr.length, REC_ALIGN_ORDER);
+
+ if ( datasz )
+ {
+ if ( !rrctx->data )
+ {
+ rrctx->data = malloc(datasz);
+
+ if ( !rrctx->data )
+ {
+ ERROR("Unable to allocate %zu bytes for record (0x%08x, %s)",
+ datasz, rrctx->rhdr.type,
+ rec_type_to_str(rrctx->rhdr.type));
+ return -1;
+ }
+ }
+
+ dataoff = rrctx->offset - sizeof(rrctx->rhdr);
+ rc = try_read_exact(fd, (char *)rrctx->data + dataoff, datasz -
dataoff,
+ &offset_out);
+ rrctx->offset += offset_out;
+
+ if ( rc == -1 )
+ {
+ /* Differentiate between expected and fatal errors. */
+ if ( (errno != EAGAIN) && (errno != EWOULDBLOCK) )
+ {
+ free(rrctx->data);
+ rrctx->data = NULL;
+ PERROR("Failed to read %zu bytes for record (0x%08x, %s)",
+ datasz, rrctx->rhdr.type,
+ rec_type_to_str(rrctx->rhdr.type));
+ }
+
+ return rc;
+ }
+ }
+
+ /* Success! Fill in the output record structure. */
+ rec->type = rrctx->rhdr.type;
+ rec->length = rrctx->rhdr.length;
+ rec->data = rrctx->data;
+ rrctx->data = NULL;
+
+ return 0;
+}
+
int validate_pages_record(struct xc_sr_context *ctx, struct xc_sr_record *rec,
uint32_t expected_type)
{
diff --git a/tools/libxc/xc_sr_common.h b/tools/libxc/xc_sr_common.h
index fc82e71..ce72e0d 100644
--- a/tools/libxc/xc_sr_common.h
+++ b/tools/libxc/xc_sr_common.h
@@ -399,6 +399,45 @@ static inline int write_record(struct xc_sr_context *ctx,
int fd,
int read_record(struct xc_sr_context *ctx, int fd, struct xc_sr_record *rec);
/*
+ * try_read_record() (prototype below) reads a record from a _non-blocking_
+ * stream over the course of one or more invocations. Context for the record
+ * read is maintained in an xc_sr_read_record_context.
+ *
+ * The protocol is:
+ * - call read_record_init() on an uninitialized or previously-destroyed
+ * read-record context prior to using it to read a record
+ * - call try_read_record() with this initialized context one or more times
+ * - rc < 0 and errno == EAGAIN/EWOULDBLOCK => try again
+ * - rc < 0 otherwise => failure
+ * - rc == 0 => a complete record has been read, and is filled into
+ * try_read_record()'s rec argument
+ * - after either failure or completion of a record, destroy the context with
+ * read_record_destroy()
+ */
+struct xc_sr_read_record_context
+{
+ struct xc_sr_context *ctx;
+ size_t offset;
+ struct xc_sr_rhdr rhdr;
+ void *data;
+};
+
+static inline void read_record_init(struct xc_sr_read_record_context *rrctx,
+ struct xc_sr_context *ctx)
+{
+ *rrctx = (struct xc_sr_read_record_context) { .ctx = ctx };
+}
+
+int try_read_record(struct xc_sr_read_record_context *rrctx, int fd,
+ struct xc_sr_record *rec);
+
+static inline void read_record_destroy(struct xc_sr_read_record_context *rrctx)
+{
+ free(rrctx->data);
+ rrctx->data = NULL;
+}
+
+/*
* Given a record of one of the page data types, validate it by:
* - checking its actual type against its specific expected type
* - sanity checking its actual length against its claimed length
--
2.7.4
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |