diff options
-rw-r--r-- | samples/client.c | 32 | ||||
-rw-r--r-- | samples/server.c | 131 |
2 files changed, 53 insertions, 110 deletions
diff --git a/samples/client.c b/samples/client.c index fc662fd..f32a060 100644 --- a/samples/client.c +++ b/samples/client.c @@ -754,9 +754,6 @@ do_migrate(int sock, int migr_reg_index, size_t nr_iters, strerror(-ret)); } - /* We do expect some migration data. */ - assert(pending_bytes > 0); - for (i = 0; i < nr_iters && pending_bytes > 0; i++) { /* XXX read data_offset and data_size */ @@ -827,17 +824,18 @@ fake_guest(void *arg) err(EXIT_FAILURE, "failed to open /dev/urandom"); } - MD5_Init(&md5_ctx); do { ret = fread(buf, fake_guest_data->bar1_size, 1, fp); if (ret != 1) { errx(EXIT_FAILURE, "short read %d", ret); } - ret = access_region(fake_guest_data->sock, 1, true, 0, buf, sizeof buf); + ret = access_region(fake_guest_data->sock, 1, true, 0, buf, + fake_guest_data->bar1_size); if (ret != 0) { err(EXIT_FAILURE, "fake guest failed to write garbage to BAR1"); } + MD5_Init(&md5_ctx); MD5_Update(&md5_ctx, buf, fake_guest_data->bar1_size); __sync_synchronize(); } while (!fake_guest_data->done); @@ -897,12 +895,6 @@ migrate_from(int sock, int migr_reg_index, size_t *nr_iters, } _nr_iters = do_migrate(sock, migr_reg_index, 3, *migr_iters); - if (_nr_iters != 3) { - errx(EXIT_FAILURE, - "expected 3 iterations instead of %ld while in pre-copy state\n", - _nr_iters); - } - printf("stopping fake guest thread\n"); fake_guest_data.done = true; __sync_synchronize(); @@ -913,11 +905,6 @@ migrate_from(int sock, int migr_reg_index, size_t *nr_iters, } _nr_iters += do_migrate(sock, migr_reg_index, 1, (*migr_iters) + _nr_iters); - if (_nr_iters != 4) { - errx(EXIT_FAILURE, - "expected 4 iterations instead of %ld while in pre-copy state\n", - _nr_iters); - } printf("setting device state to stop-and-copy\n"); @@ -931,9 +918,9 @@ migrate_from(int sock, int migr_reg_index, size_t *nr_iters, } _nr_iters += do_migrate(sock, migr_reg_index, 1, (*migr_iters) + _nr_iters); - if (_nr_iters != 5) { + if (_nr_iters != 2) { errx(EXIT_FAILURE, - "expected 5 iterations instead of %ld while in stop-and-copy state\n", + "expected 2 iterations instead of %ld while in stop-and-copy state\n", _nr_iters); } @@ -1074,9 +1061,9 @@ migrate_to(char *old_sock_path, int *server_max_fds, MD5_Update(&md5_ctx, buf, bar1_size); MD5_Final(dst_md5sum, &md5_ctx); - if (strcmp((char*)src_md5sum, (char*)dst_md5sum) != 0) { + if (strncmp((char*)src_md5sum, (char*)dst_md5sum, MD5_DIGEST_LENGTH) != 0) { int i; - fprintf(stderr, "md5 sum mismatch: "); + fprintf(stderr, "md5sum mismatch: "); for (i = 0; i < MD5_DIGEST_LENGTH; i++) { fprintf(stderr, "%02x", src_md5sum[i]); } @@ -1085,6 +1072,7 @@ migrate_to(char *old_sock_path, int *server_max_fds, fprintf(stderr, "%02x", dst_md5sum[i]); } fprintf(stderr, "\n"); + abort(); } return sock; @@ -1299,8 +1287,8 @@ int main(int argc, char *argv[]) */ sleep(1); - migrate_from(sock, migr_reg_index, &nr_iters, &migr_iters, md5sum, - bar1_size); + nr_iters = migrate_from(sock, migr_reg_index, &nr_iters, &migr_iters, + md5sum, bar1_size); /* * Normally the client would now send the device state to the destination diff --git a/samples/server.c b/samples/server.c index 82b22ff..35452c3 100644 --- a/samples/server.c +++ b/samples/server.c @@ -63,13 +63,6 @@ struct server_data { struct dma_regions regions[NR_DMA_REGIONS]; struct { __u64 pending_bytes; - - /* - * TODO must be maximum size of migration data read, we'll use that to - * create the migration region. - */ - size_t migr_data_len; - vfu_migr_state_t state; } migration; }; @@ -137,22 +130,10 @@ bar1_access(vfu_ctx_t *vfu_ctx, char * const buf, } if (is_write) { - /* - * FIXME this doesn't work for the following reason: - * The amount of migration data the server generates during the pre-copy - * and stop-and-copy phases is larger than the size of BAR1, however - * during the resuming state, the server blindly appends to BAR1, - * since it cannot know that a particular piece of migration data has - * to be written to a specific offset. To fix this we have to include - * offset and length, along with the actual data, when reading migration - * data. - */ -#if 0 if (server_data->migration.state == VFU_MIGR_STATE_PRE_COPY) { /* dirty the whole thing */ server_data->migration.pending_bytes = server_data->bar1_size; } -#endif memcpy(server_data->bar1 + offset, buf, count); } else { memcpy(buf, server_data->bar1, count); @@ -285,7 +266,7 @@ migration_device_state_transition(vfu_ctx_t *vfu_ctx, vfu_migr_state_t state) switch (state) { case VFU_MIGR_STATE_STOP_AND_COPY: - server_data->migration.pending_bytes = sizeof(time_t); /* FIXME BAR0 region size */ + server_data->migration.pending_bytes = server_data->bar1_size + sizeof(time_t); /* FIXME BAR0 region size */ break; case VFU_MIGR_STATE_PRE_COPY: /* TODO must be less than size of data region in migration region */ @@ -322,15 +303,10 @@ migration_prepare_data(vfu_ctx_t *vfu_ctx, __u64 *offset, __u64 *size) { struct server_data *server_data = vfu_get_private(vfu_ctx); - if (server_data->migration.state == VFU_MIGR_STATE_PRE_COPY) { - assert(server_data->bar1_size >= server_data->migration.pending_bytes); - *offset = server_data->bar1_size - server_data->migration.pending_bytes; - } else if (server_data->migration.state == VFU_MIGR_STATE_STOP_AND_COPY) { - *offset = 0; - } else { - assert(false); /* FIXME fail gracefully */ + *offset = 0; + if (size != NULL) { + *size = server_data->migration.pending_bytes; } - *size = server_data->migration.pending_bytes; return 0; } @@ -338,49 +314,35 @@ static ssize_t migration_read_data(vfu_ctx_t *vfu_ctx, void *buf, __u64 size, __u64 offset) { struct server_data *server_data = vfu_get_private(vfu_ctx); - uint8_t *p; - size_t bar_size; - /* FIXME need to validate data range */ - vfu_log(vfu_ctx, LOG_DEBUG, "read migration data %#llx-%#llx, %#llx remaining", - offset, offset + size - 1, server_data->migration.pending_bytes); - - assert(size <= server_data->migration.pending_bytes); + if (server_data->migration.state != VFU_MIGR_STATE_PRE_COPY && + server_data->migration.state != VFU_MIGR_STATE_STOP_AND_COPY) + { + return size; + } /* - * If in pre-copy state we copy BAR1, if in stop-and-copy state we copy - * BAR0. This behavior is purely an artifact of this server implementation - * simply to make it as simple as possible. Note that the client might go - * from state running to stop-and-copy, completely skipping the pre-copy - * state. This is legitimate but we don't support it for now. + * For ease of implementation we expect the client to read all migration + * data in one go; partial reads are not supported. This is allowed by VFIO + * however we don't yet support it. Similarly, when resuming, partial + * writes are supported by VFIO, however we don't in this sample. * - * FIXME implement transitioning from the running state straight to the - * stop-and-copy state. + * If in pre-copy state we copy BAR1, if in stop-and-copy state we copy + * both BAR1 and BAR0. Since we always copy BAR1 in the stop-and-copy state, + * copying BAR1 in the pre-copy state is pointless. Fixing this requires + * more complex state tracking which exceeds the scope of this sample. */ - if (server_data->migration.state == VFU_MIGR_STATE_PRE_COPY) { - p = server_data->bar1; - bar_size = server_data->bar1_size; - } else if (server_data->migration.state == VFU_MIGR_STATE_STOP_AND_COPY) { - p = (uint8_t*)&server_data->bar0; - bar_size = sizeof server_data->bar0; - } else { - /* - * Reading from the migration region in any other state is undefined - * (I think). - */ - assert(false); - return 0; - } - if (offset > bar_size) { - errno = EINVAL; - return -1; + if (offset != 0 || size != server_data->migration.pending_bytes) { + return -EINVAL; } - if (offset + size > bar_size) { - size = bar_size - offset; + + memcpy(buf, server_data->bar1, server_data->bar1_size); + if (server_data->migration.state == VFU_MIGR_STATE_STOP_AND_COPY) { + memcpy(buf + server_data->bar1_size, &server_data->bar0, + sizeof server_data->bar0); } - memcpy(buf, p + offset, size); - server_data->migration.pending_bytes -= size; + server_data->migration.pending_bytes = 0; return size; } @@ -389,36 +351,30 @@ static ssize_t migration_write_data(vfu_ctx_t *vfu_ctx, void *data, __u64 size, __u64 offset) { struct server_data *server_data = vfu_get_private(vfu_ctx); + char *buf = data; + int ret; assert(server_data != NULL); assert(data != NULL); - /* - * During pre-copy state we save BAR1 and during stop-and-copy state we - * save BAR0. - */ - vfu_log(vfu_ctx, LOG_DEBUG, - "apply device migration data %#llx-%#llx", - offset, offset + size - 1); - - if (offset < server_data->bar1_size) { - __u64 _size = MIN(size, server_data->bar1_size - offset); - memcpy(server_data->bar1 + offset, data, _size); - offset += _size; - size -= _size; + if (offset != 0 || size < server_data->bar1_size) { + vfu_log(vfu_ctx, LOG_DEBUG, "XXX bad migration data write %#llx-%#llx", + offset, offset + size - 1); + return -EINVAL; } - if (offset >= server_data->bar1_size && size > 0) { - int ret; - - /* FIXME should be able to write any valid subrange */ - assert(offset - server_data->bar1_size == 0); - assert(size == sizeof server_data->bar0); - - ret = bar0_access(vfu_ctx, data, sizeof server_data->bar0, 0, true); - - assert(ret == (int)size); /* FIXME */ + memcpy(server_data->bar1, buf, server_data->bar1_size); + buf += server_data->bar1_size; + size -= server_data->bar1_size; + if (size == 0) { + return 0; + } + if (size != sizeof server_data->bar0) { + return -EINVAL; } + memcpy(&server_data->bar0, buf, sizeof server_data->bar0); + ret = bar0_access(vfu_ctx, buf, sizeof server_data->bar0, 0, true); + assert(ret == (int)size); /* FIXME */ return 0; } @@ -446,7 +402,6 @@ int main(int argc, char *argv[]) size_t bar1_size = 0x3000; struct server_data server_data = { .migration = { - .migr_data_len = bar1_size + sizeof(time_t), .state = VFU_MIGR_STATE_RUNNING } }; @@ -542,7 +497,7 @@ int main(int argc, char *argv[]) } vfu_migration_t migration = { - .size = server_data.migration.migr_data_len, + .size = bar1_size + sizeof(time_t), .mmap_areas = mmap_areas, .nr_mmap_areas = 2, .callbacks = { |