mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
tools/libxl: Extend datacopier to support reading into a buffer
Currently a datacopier may source its data from an fd or local buffer, but its destination must be an fd. For migration v2, libxl needs to read from the migration stream into a local buffer. Implement a "read into local buffer" mode, invoked when readbuf is set and writefd is -1. On success, the callback passes the number of bytes read. Signed-off-by: Ross Lagerwall <ross.lagerwall@citrix.com> [Rewrite commit message] Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com> CC: Ian Campbell <Ian.Campbell@citrix.com> CC: Ian Jackson <Ian.Jackson@eu.citrix.com> CC: Wei Liu <wei.liu2@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com>
This commit is contained in:
1 parent
c9f8db9b16
commit
6d896e1357
2 files changed
+42
-25
No files matched your search
+36
-23
@@ -134,7 +134,7 @@ static void datacopier_check_state(libxl__egc *egc, libxl__datacopier_state *dc)
|
||||
STATE_AO_GC(dc->ao);
|
||||
int rc;
|
||||
|
||||
if (dc->used) {
|
||||
if (dc->used && !dc->readbuf) {
|
||||
if (!libxl__ev_fd_isregistered(&dc->towrite)) {
|
||||
rc = libxl__ev_fd_register(gc, &dc->towrite, datacopier_writable,
|
||||
dc->writefd, POLLOUT);
|
||||
@@ -148,7 +148,7 @@ static void datacopier_check_state(libxl__egc *egc, libxl__datacopier_state *dc)
|
||||
} else if (!libxl__ev_fd_isregistered(&dc->toread) ||
|
||||
dc->bytes_to_read == 0) {
|
||||
/* we have had eof */
|
||||
datacopier_callback(egc, dc, 0, 0);
|
||||
datacopier_callback(egc, dc, 0, dc->readbuf ? dc->used : 0);
|
||||
return;
|
||||
} else {
|
||||
/* nothing buffered, but still reading */
|
||||
@@ -216,25 +216,31 @@ static void datacopier_readable(libxl__egc *egc, libxl__ev_fd *ev,
|
||||
}
|
||||
assert(revents & POLLIN);
|
||||
for (;;) {
|
||||
while (dc->used >= dc->maxsz) {
|
||||
libxl__datacopier_buf *rm = LIBXL_TAILQ_FIRST(&dc->bufs);
|
||||
dc->used -= rm->used;
|
||||
assert(dc->used >= 0);
|
||||
LIBXL_TAILQ_REMOVE(&dc->bufs, rm, entry);
|
||||
free(rm);
|
||||
}
|
||||
libxl__datacopier_buf *buf = NULL;
|
||||
int r;
|
||||
|
||||
libxl__datacopier_buf *buf =
|
||||
LIBXL_TAILQ_LAST(&dc->bufs, libxl__datacopier_bufs);
|
||||
if (!buf || buf->used >= sizeof(buf->buf)) {
|
||||
buf = malloc(sizeof(*buf));
|
||||
if (!buf) libxl__alloc_failed(CTX, __func__, 1, sizeof(*buf));
|
||||
buf->used = 0;
|
||||
LIBXL_TAILQ_INSERT_TAIL(&dc->bufs, buf, entry);
|
||||
}
|
||||
int r = read(ev->fd, buf->buf + buf->used,
|
||||
if (dc->readbuf) {
|
||||
r = read(ev->fd, dc->readbuf + dc->used, dc->bytes_to_read);
|
||||
} else {
|
||||
while (dc->used >= dc->maxsz) {
|
||||
libxl__datacopier_buf *rm = LIBXL_TAILQ_FIRST(&dc->bufs);
|
||||
dc->used -= rm->used;
|
||||
assert(dc->used >= 0);
|
||||
LIBXL_TAILQ_REMOVE(&dc->bufs, rm, entry);
|
||||
free(rm);
|
||||
}
|
||||
|
||||
buf = LIBXL_TAILQ_LAST(&dc->bufs, libxl__datacopier_bufs);
|
||||
if (!buf || buf->used >= sizeof(buf->buf)) {
|
||||
buf = malloc(sizeof(*buf));
|
||||
if (!buf) libxl__alloc_failed(CTX, __func__, 1, sizeof(*buf));
|
||||
buf->used = 0;
|
||||
LIBXL_TAILQ_INSERT_TAIL(&dc->bufs, buf, entry);
|
||||
}
|
||||
r = read(ev->fd, buf->buf + buf->used,
|
||||
min_t(size_t, sizeof(buf->buf) - buf->used,
|
||||
(dc->bytes_to_read == -1) ? SIZE_MAX : dc->bytes_to_read));
|
||||
}
|
||||
if (r < 0) {
|
||||
if (errno == EINTR) continue;
|
||||
if (errno == EWOULDBLOCK) break;
|
||||
@@ -257,9 +263,11 @@ static void datacopier_readable(libxl__egc *egc, libxl__ev_fd *ev,
|
||||
return;
|
||||
}
|
||||
}
|
||||
buf->used += r;
|
||||
if (!dc->readbuf) {
|
||||
buf->used += r;
|
||||
assert(buf->used <= sizeof(buf->buf));
|
||||
}
|
||||
dc->used += r;
|
||||
assert(buf->used <= sizeof(buf->buf));
|
||||
if (dc->bytes_to_read > 0)
|
||||
dc->bytes_to_read -= r;
|
||||
if (dc->bytes_to_read == 0)
|
||||
@@ -318,15 +326,20 @@ int libxl__datacopier_start(libxl__datacopier_state *dc)
|
||||
|
||||
libxl__datacopier_init(dc);
|
||||
|
||||
assert(dc->readfd >= 0 || dc->writefd >= 0);
|
||||
assert(!(dc->readbuf && dc->bytes_to_read == -1));
|
||||
|
||||
if (dc->readfd >= 0) {
|
||||
rc = libxl__ev_fd_register(gc, &dc->toread, datacopier_readable,
|
||||
dc->readfd, POLLIN);
|
||||
if (rc) goto out;
|
||||
}
|
||||
|
||||
rc = libxl__ev_fd_register(gc, &dc->towrite, datacopier_writable,
|
||||
dc->writefd, POLLOUT);
|
||||
if (rc) goto out;
|
||||
if (dc->writefd >= 0) {
|
||||
rc = libxl__ev_fd_register(gc, &dc->towrite, datacopier_writable,
|
||||
dc->writefd, POLLOUT);
|
||||
if (rc) goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
@@ -2524,8 +2524,9 @@ typedef struct libxl__datacopier_buf libxl__datacopier_buf;
|
||||
|
||||
/* onwrite==1 means failure happened when writing, logged, errnoval is valid
|
||||
* onwrite==0 means failure happened when reading
|
||||
* errnoval==0 means we got eof and all data was written
|
||||
* errnoval!=0 means we had a read error, logged
|
||||
* errnoval>=0 means we got eof and all data was written or number of bytes
|
||||
* written when in read mode
|
||||
* errnoval<0 means we had a read error, logged
|
||||
* onwrite==-1 means some other internal failure, errnoval not valid, logged
|
||||
* If we get POLLHUP, we call callback_pollhup(..., onwrite, -1);
|
||||
* or if callback_pollhup==0 this is an internal failure, as above.
|
||||
@@ -2550,6 +2551,9 @@ struct libxl__datacopier_state {
|
||||
FILE *log; /* gets a copy of everything */
|
||||
libxl__datacopier_callback *callback;
|
||||
libxl__datacopier_callback *callback_pollhup;
|
||||
void *readbuf; /* Set this to read data into it without writing to an
|
||||
fd. The buffer should be at least as large as the
|
||||
bytes_to_read parameter, which should not be -1. */
|
||||
/* remaining fields are private to datacopier */
|
||||
libxl__ev_fd toread, towrite;
|
||||
ssize_t used;
|
||||
|
||||