[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 |