Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/snapshot.c
Show First 20 Lines • Show All 880 Lines • ▼ Show 20 Lines | vm_restore_kern_struct(struct vmctx *ctx, struct restore_state *rstate, | ||||
if (struct_size == 0) { | if (struct_size == 0) { | ||||
fprintf(stderr, "%s: Kernel struct size was 0 for: %s\r\n", | fprintf(stderr, "%s: Kernel struct size was 0 for: %s\r\n", | ||||
__func__, info->struct_name); | __func__, info->struct_name); | ||||
ret = -1; | ret = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
meta = &(struct vm_snapshot_meta) { | meta = &(struct vm_snapshot_meta) { | ||||
.ctx = ctx, | |||||
.dev_name = info->struct_name, | .dev_name = info->struct_name, | ||||
.dev_req = info->req, | .dev_req = info->req, | ||||
.buffer.buf_start = struct_ptr, | .buffer.buf_start = struct_ptr, | ||||
.buffer.buf_size = struct_size, | .buffer.buf_size = struct_size, | ||||
.buffer.buf = struct_ptr, | .buffer.buf = struct_ptr, | ||||
.buffer.buf_rem = struct_size, | .buffer.buf_rem = struct_size, | ||||
.op = VM_SNAPSHOT_RESTORE, | .op = VM_SNAPSHOT_RESTORE, | ||||
}; | }; | ||||
ret = vm_snapshot_req(meta); | ret = vm_snapshot_req(ctx, meta); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "%s: Failed to restore struct: %s\r\n", | fprintf(stderr, "%s: Failed to restore struct: %s\r\n", | ||||
__func__, info->struct_name); | __func__, info->struct_name); | ||||
goto done; | goto done; | ||||
} | } | ||||
done: | done: | ||||
return (ret); | return (ret); | ||||
Show All 11 Lines | for (i = 0; i < nitems(snapshot_kern_structs); i++) { | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vm_restore_user_dev(struct vmctx *ctx, struct restore_state *rstate, | vm_restore_user_dev(struct restore_state *rstate, | ||||
const struct vm_snapshot_dev_info *info) | const struct vm_snapshot_dev_info *info) | ||||
{ | { | ||||
void *dev_ptr; | void *dev_ptr; | ||||
size_t dev_size; | size_t dev_size; | ||||
int ret; | int ret; | ||||
struct vm_snapshot_meta *meta; | struct vm_snapshot_meta *meta; | ||||
dev_ptr = lookup_dev(info->dev_name, rstate, &dev_size); | dev_ptr = lookup_dev(info->dev_name, rstate, &dev_size); | ||||
if (dev_ptr == NULL) { | if (dev_ptr == NULL) { | ||||
fprintf(stderr, "Failed to lookup dev: %s\r\n", info->dev_name); | fprintf(stderr, "Failed to lookup dev: %s\r\n", info->dev_name); | ||||
fprintf(stderr, "Continuing the restore/migration process\r\n"); | fprintf(stderr, "Continuing the restore/migration process\r\n"); | ||||
return (0); | return (0); | ||||
} | } | ||||
if (dev_size == 0) { | if (dev_size == 0) { | ||||
fprintf(stderr, "%s: Device size is 0. " | fprintf(stderr, "%s: Device size is 0. " | ||||
"Assuming %s is not used\r\n", | "Assuming %s is not used\r\n", | ||||
__func__, info->dev_name); | __func__, info->dev_name); | ||||
return (0); | return (0); | ||||
} | } | ||||
meta = &(struct vm_snapshot_meta) { | meta = &(struct vm_snapshot_meta) { | ||||
.ctx = ctx, | |||||
.dev_name = info->dev_name, | .dev_name = info->dev_name, | ||||
.buffer.buf_start = dev_ptr, | .buffer.buf_start = dev_ptr, | ||||
.buffer.buf_size = dev_size, | .buffer.buf_size = dev_size, | ||||
.buffer.buf = dev_ptr, | .buffer.buf = dev_ptr, | ||||
.buffer.buf_rem = dev_size, | .buffer.buf_rem = dev_size, | ||||
.op = VM_SNAPSHOT_RESTORE, | .op = VM_SNAPSHOT_RESTORE, | ||||
}; | }; | ||||
ret = (*info->snapshot_cb)(meta); | ret = (*info->snapshot_cb)(meta); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "Failed to restore dev: %s\r\n", | fprintf(stderr, "Failed to restore dev: %s\r\n", | ||||
info->dev_name); | info->dev_name); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
int | int | ||||
vm_restore_user_devs(struct vmctx *ctx, struct restore_state *rstate) | vm_restore_user_devs(struct restore_state *rstate) | ||||
{ | { | ||||
size_t i; | size_t i; | ||||
int ret; | int ret; | ||||
for (i = 0; i < nitems(snapshot_devs); i++) { | for (i = 0; i < nitems(snapshot_devs); i++) { | ||||
ret = vm_restore_user_dev(ctx, rstate, &snapshot_devs[i]); | ret = vm_restore_user_dev(rstate, &snapshot_devs[i]); | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
} | } | ||||
return 0; | return 0; | ||||
} | } | ||||
int | int | ||||
Show All 32 Lines | for (i = 0; i < nitems(snapshot_devs); i++) { | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
} | } | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vm_snapshot_kern_struct(int data_fd, xo_handle_t *xop, const char *array_key, | vm_snapshot_kern_struct(struct vmctx *ctx, int data_fd, xo_handle_t *xop, | ||||
struct vm_snapshot_meta *meta, off_t *offset) | const char *array_key, struct vm_snapshot_meta *meta, off_t *offset) | ||||
{ | { | ||||
int ret; | int ret; | ||||
size_t data_size; | size_t data_size; | ||||
ssize_t write_cnt; | ssize_t write_cnt; | ||||
ret = vm_snapshot_req(meta); | ret = vm_snapshot_req(ctx, meta); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "%s: Failed to snapshot struct %s\r\n", | fprintf(stderr, "%s: Failed to snapshot struct %s\r\n", | ||||
__func__, meta->dev_name); | __func__, meta->dev_name); | ||||
ret = -1; | ret = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
data_size = vm_get_snapshot_size(meta); | data_size = vm_get_snapshot_size(meta); | ||||
Show All 36 Lines | vm_snapshot_kern_structs(struct vmctx *ctx, int data_fd, xo_handle_t *xop) | ||||
buffer = malloc(SNAPSHOT_BUFFER_SIZE * sizeof(char)); | buffer = malloc(SNAPSHOT_BUFFER_SIZE * sizeof(char)); | ||||
if (buffer == NULL) { | if (buffer == NULL) { | ||||
error = ENOMEM; | error = ENOMEM; | ||||
perror("Failed to allocate memory for snapshot buffer"); | perror("Failed to allocate memory for snapshot buffer"); | ||||
goto err_vm_snapshot_kern_data; | goto err_vm_snapshot_kern_data; | ||||
} | } | ||||
meta = &(struct vm_snapshot_meta) { | meta = &(struct vm_snapshot_meta) { | ||||
.ctx = ctx, | |||||
.buffer.buf_start = buffer, | .buffer.buf_start = buffer, | ||||
.buffer.buf_size = buf_size, | .buffer.buf_size = buf_size, | ||||
.op = VM_SNAPSHOT_SAVE, | .op = VM_SNAPSHOT_SAVE, | ||||
}; | }; | ||||
xo_open_list_h(xop, JSON_STRUCT_ARR_KEY); | xo_open_list_h(xop, JSON_STRUCT_ARR_KEY); | ||||
for (i = 0; i < nitems(snapshot_kern_structs); i++) { | for (i = 0; i < nitems(snapshot_kern_structs); i++) { | ||||
meta->dev_name = snapshot_kern_structs[i].struct_name; | meta->dev_name = snapshot_kern_structs[i].struct_name; | ||||
meta->dev_req = snapshot_kern_structs[i].req; | meta->dev_req = snapshot_kern_structs[i].req; | ||||
memset(meta->buffer.buf_start, 0, meta->buffer.buf_size); | memset(meta->buffer.buf_start, 0, meta->buffer.buf_size); | ||||
meta->buffer.buf = meta->buffer.buf_start; | meta->buffer.buf = meta->buffer.buf_start; | ||||
meta->buffer.buf_rem = meta->buffer.buf_size; | meta->buffer.buf_rem = meta->buffer.buf_size; | ||||
ret = vm_snapshot_kern_struct(data_fd, xop, JSON_DEV_ARR_KEY, | ret = vm_snapshot_kern_struct(ctx, data_fd, xop, | ||||
meta, &offset); | JSON_DEV_ARR_KEY, meta, &offset); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
error = -1; | error = -1; | ||||
goto err_vm_snapshot_kern_data; | goto err_vm_snapshot_kern_data; | ||||
} | } | ||||
} | } | ||||
xo_close_list_h(xop, JSON_STRUCT_ARR_KEY); | xo_close_list_h(xop, JSON_STRUCT_ARR_KEY); | ||||
err_vm_snapshot_kern_data: | err_vm_snapshot_kern_data: | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | ret = vm_snapshot_dev_write_data(data_fd, xop, JSON_DEV_ARR_KEY, meta, | ||||
offset); | offset); | ||||
if (ret != 0) | if (ret != 0) | ||||
return (ret); | return (ret); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | static int | ||||
vm_snapshot_user_devs(struct vmctx *ctx, int data_fd, xo_handle_t *xop) | vm_snapshot_user_devs(int data_fd, xo_handle_t *xop) | ||||
{ | { | ||||
int ret; | int ret; | ||||
off_t offset; | off_t offset; | ||||
void *buffer; | void *buffer; | ||||
size_t buf_size, i; | size_t buf_size, i; | ||||
struct vm_snapshot_meta *meta; | struct vm_snapshot_meta *meta; | ||||
buf_size = SNAPSHOT_BUFFER_SIZE; | buf_size = SNAPSHOT_BUFFER_SIZE; | ||||
offset = lseek(data_fd, 0, SEEK_CUR); | offset = lseek(data_fd, 0, SEEK_CUR); | ||||
if (offset < 0) { | if (offset < 0) { | ||||
perror("Failed to get data file current offset."); | perror("Failed to get data file current offset."); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
buffer = malloc(buf_size); | buffer = malloc(buf_size); | ||||
if (buffer == NULL) { | if (buffer == NULL) { | ||||
perror("Failed to allocate memory for snapshot buffer"); | perror("Failed to allocate memory for snapshot buffer"); | ||||
ret = ENOSPC; | ret = ENOSPC; | ||||
goto snapshot_err; | goto snapshot_err; | ||||
} | } | ||||
meta = &(struct vm_snapshot_meta) { | meta = &(struct vm_snapshot_meta) { | ||||
.ctx = ctx, | |||||
.buffer.buf_start = buffer, | .buffer.buf_start = buffer, | ||||
.buffer.buf_size = buf_size, | .buffer.buf_size = buf_size, | ||||
.op = VM_SNAPSHOT_SAVE, | .op = VM_SNAPSHOT_SAVE, | ||||
}; | }; | ||||
xo_open_list_h(xop, JSON_DEV_ARR_KEY); | xo_open_list_h(xop, JSON_DEV_ARR_KEY); | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | vm_checkpoint(struct vmctx *ctx, const char *checkpoint_file, bool stop_vm) | ||||
ret = vm_snapshot_kern_structs(ctx, kdata_fd, xop); | ret = vm_snapshot_kern_structs(ctx, kdata_fd, xop); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "Failed to snapshot vm kernel data.\n"); | fprintf(stderr, "Failed to snapshot vm kernel data.\n"); | ||||
error = -1; | error = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
ret = vm_snapshot_user_devs(ctx, kdata_fd, xop); | ret = vm_snapshot_user_devs(kdata_fd, xop); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "Failed to snapshot device state.\n"); | fprintf(stderr, "Failed to snapshot device state.\n"); | ||||
error = -1; | error = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
xo_finish_h(xop); | xo_finish_h(xop); | ||||
▲ Show 20 Lines • Show All 227 Lines • ▼ Show 20 Lines | vm_get_snapshot_size(struct vm_snapshot_meta *meta) | ||||
} else { | } else { | ||||
length = buffer->buf_size - buffer->buf_rem; | length = buffer->buf_size - buffer->buf_rem; | ||||
} | } | ||||
return (length); | return (length); | ||||
} | } | ||||
int | int | ||||
vm_snapshot_guest2host_addr(void **addrp, size_t len, bool restore_null, | vm_snapshot_guest2host_addr(struct vmctx *ctx, void **addrp, size_t len, | ||||
struct vm_snapshot_meta *meta) | bool restore_null, struct vm_snapshot_meta *meta) | ||||
{ | { | ||||
int ret; | int ret; | ||||
vm_paddr_t gaddr; | vm_paddr_t gaddr; | ||||
if (meta->op == VM_SNAPSHOT_SAVE) { | if (meta->op == VM_SNAPSHOT_SAVE) { | ||||
gaddr = paddr_host2guest(meta->ctx, *addrp); | gaddr = paddr_host2guest(ctx, *addrp); | ||||
if (gaddr == (vm_paddr_t) -1) { | if (gaddr == (vm_paddr_t) -1) { | ||||
if (!restore_null || | if (!restore_null || | ||||
(restore_null && (*addrp != NULL))) { | (restore_null && (*addrp != NULL))) { | ||||
ret = EFAULT; | ret = EFAULT; | ||||
goto done; | goto done; | ||||
} | } | ||||
} | } | ||||
SNAPSHOT_VAR_OR_LEAVE(gaddr, meta, ret, done); | SNAPSHOT_VAR_OR_LEAVE(gaddr, meta, ret, done); | ||||
} else if (meta->op == VM_SNAPSHOT_RESTORE) { | } else if (meta->op == VM_SNAPSHOT_RESTORE) { | ||||
SNAPSHOT_VAR_OR_LEAVE(gaddr, meta, ret, done); | SNAPSHOT_VAR_OR_LEAVE(gaddr, meta, ret, done); | ||||
if (gaddr == (vm_paddr_t) -1) { | if (gaddr == (vm_paddr_t) -1) { | ||||
if (!restore_null) { | if (!restore_null) { | ||||
ret = EFAULT; | ret = EFAULT; | ||||
goto done; | goto done; | ||||
} | } | ||||
} | } | ||||
*addrp = paddr_guest2host(meta->ctx, gaddr, len); | *addrp = paddr_guest2host(ctx, gaddr, len); | ||||
} else { | } else { | ||||
ret = EINVAL; | ret = EINVAL; | ||||
} | } | ||||
done: | done: | ||||
return (ret); | return (ret); | ||||
} | } | ||||
Show All 32 Lines |