Changeset View
Changeset View
Standalone View
Standalone View
usr.sbin/bhyve/snapshot.c
Show First 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | const struct vm_snapshot_kern_info snapshot_kern_structs[] = { | ||||
{ "vrtc", STRUCT_VRTC }, | { "vrtc", STRUCT_VRTC }, | ||||
}; | }; | ||||
static cpuset_t vcpus_active, vcpus_suspended; | static cpuset_t vcpus_active, vcpus_suspended; | ||||
static pthread_mutex_t vcpu_lock; | static pthread_mutex_t vcpu_lock; | ||||
static pthread_cond_t vcpus_idle, vcpus_can_run; | static pthread_cond_t vcpus_idle, vcpus_can_run; | ||||
static bool checkpoint_active; | static bool checkpoint_active; | ||||
static int cdir_fd = -1; | static int cdir_fd = AT_FDCWD; | ||||
/* | /* | ||||
* TODO: Harden this function and all of its callers since 'base_str' is a user | * TODO: Harden this function and all of its callers since 'base_str' is a user | ||||
* provided string. | * provided string. | ||||
*/ | */ | ||||
static char * | static char * | ||||
strcat_extension(const char *base_str, const char *ext) | strcat_extension(const char *base_str, const char *ext) | ||||
{ | { | ||||
char *res; | char *res; | ||||
▲ Show 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
cap_rights_t rights; | cap_rights_t rights; | ||||
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R, CAP_READ); | cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R, CAP_READ); | ||||
if (caph_rights_limit(s, &rights) == -1) | if (caph_rights_limit(s, &rights) == -1) | ||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | errx(EX_OSERR, "Unable to apply rights for sandbox"); | ||||
} | } | ||||
static void | |||||
limit_metadata_socket(int s) | |||||
{ | |||||
cap_rights_t rights; | |||||
cap_rights_init(&rights, CAP_FSTAT, CAP_MMAP_R, CAP_READ); | |||||
if (caph_rights_limit(s, &rights) == -1) | |||||
errx(EX_OSERR, "Unable to apply rights for sandbox"); | |||||
} | |||||
#endif | #endif | ||||
static int | static int | ||||
load_vmmem_file(const char *filename, struct restore_state *rstate) | load_vmmem_file(const char *filename, struct restore_state *rstate) | ||||
{ | { | ||||
struct stat sb; | struct stat sb; | ||||
int err; | int err; | ||||
▲ Show 20 Lines • Show All 71 Lines • ▼ Show 20 Lines | err_load_kdata: | ||||
return (-1); | return (-1); | ||||
} | } | ||||
static int | static int | ||||
load_metadata_file(const char *filename, struct restore_state *rstate) | load_metadata_file(const char *filename, struct restore_state *rstate) | ||||
{ | { | ||||
const ucl_object_t *obj; | const ucl_object_t *obj; | ||||
struct ucl_parser *parser; | struct ucl_parser *parser; | ||||
int md_fd = -1; | |||||
int err; | int err; | ||||
parser = ucl_parser_new(UCL_PARSER_DEFAULT); | parser = ucl_parser_new(UCL_PARSER_DEFAULT); | ||||
if (parser == NULL) { | if (parser == NULL) { | ||||
fprintf(stderr, "Failed to initialize UCL parser.\n"); | fprintf(stderr, "Failed to initialize UCL parser.\n"); | ||||
goto err_load_metadata; | goto err_load_metadata; | ||||
} | } | ||||
err = ucl_parser_add_file(parser, filename); | md_fd = open(filename, O_RDONLY); | ||||
#ifndef WITHOUT_CAPSICUM | |||||
limit_metadata_socket(md_fd); | |||||
#endif | |||||
err = ucl_parser_add_fd(parser, md_fd); | |||||
if (err == 0) { | if (err == 0) { | ||||
fprintf(stderr, "Failed to parse metadata file: '%s'\n", | fprintf(stderr, "Failed to parse metadata file: '%s'\n", | ||||
filename); | filename); | ||||
err = -1; | err = -1; | ||||
goto err_load_metadata; | goto err_load_metadata; | ||||
} | } | ||||
obj = ucl_parser_get_object(parser); | obj = ucl_parser_get_object(parser); | ||||
if (obj == NULL) { | if (obj == NULL) { | ||||
fprintf(stderr, "Failed to parse object.\n"); | fprintf(stderr, "Failed to parse object.\n"); | ||||
err = -1; | err = -1; | ||||
goto err_load_metadata; | goto err_load_metadata; | ||||
} | } | ||||
rstate->meta_parser = parser; | rstate->meta_parser = parser; | ||||
rstate->meta_root_obj = (ucl_object_t *)obj; | rstate->meta_root_obj = (ucl_object_t *)obj; | ||||
return (0); | return (0); | ||||
err_load_metadata: | err_load_metadata: | ||||
if (md_fd > 0) | |||||
close(md_fd); | |||||
if (parser != NULL) | if (parser != NULL) | ||||
ucl_parser_free(parser); | ucl_parser_free(parser); | ||||
return (err); | return (err); | ||||
} | } | ||||
int | int | ||||
load_restore_file(const char *filename, struct restore_state *rstate) | load_restore_file(const char *filename, struct restore_state *rstate) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 479 Lines • ▼ Show 20 Lines | #endif /* TIOCGWINSZ */ | ||||
old_winch_handler = signal(SIGWINCH, winch_handler); | old_winch_handler = signal(SIGWINCH, winch_handler); | ||||
ret = vm_snapshot_mem_part(snapfd, 0, baseaddr, lowmem, | ret = vm_snapshot_mem_part(snapfd, 0, baseaddr, lowmem, | ||||
totalmem, op_wr); | totalmem, op_wr); | ||||
if (ret) { | if (ret) { | ||||
fprintf(stderr, "%s: Could not %s lowmem\r\n", | fprintf(stderr, "%s: Could not %s lowmem\r\n", | ||||
__func__, op_wr ? "write" : "read"); | __func__, op_wr ? "write" : "read"); | ||||
totalmem = 0; | totalmem = 0; | ||||
goto done; | |||||
} | } | ||||
if (highmem == 0) | if (highmem == 0) | ||||
goto done; | goto done; | ||||
ret = vm_snapshot_mem_part(snapfd, lowmem, baseaddr + 4*GB, | ret = vm_snapshot_mem_part(snapfd, lowmem, baseaddr + 4*GB, | ||||
highmem, totalmem, op_wr); | highmem, totalmem, op_wr); | ||||
if (ret) { | if (ret) { | ||||
▲ Show 20 Lines • Show All 533 Lines • ▼ Show 20 Lines | vm_checkpoint(struct vmctx *ctx, char *checkpoint_file, cap_channel_t *chn, bool stop_vm) | ||||
int error = 0; | int error = 0; | ||||
size_t memsz; | size_t memsz; | ||||
xo_handle_t *xop = NULL; | xo_handle_t *xop = NULL; | ||||
char *meta_filename = NULL; | char *meta_filename = NULL; | ||||
char *kdata_filename = NULL; | char *kdata_filename = NULL; | ||||
FILE *meta_file = NULL; | FILE *meta_file = NULL; | ||||
char vmname[MAX_VMNAME]; | char vmname[MAX_VMNAME]; | ||||
kdata_filename = strcat_extension(checkpoint_file, ".kern"); | kdata_filename = strcat_extension(checkpoint_file, ".kern"); | ||||
if (kdata_filename == NULL) { | if (kdata_filename == NULL) { | ||||
fprintf(stderr, "Failed to construct kernel data filename.\n"); | fprintf(stderr, "Failed to construct kernel data filename.\n"); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
kdata_fd = openat(cdir_fd, kdata_filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); | kdata_fd = openat(cdir_fd, kdata_filename, O_WRONLY | O_CREAT | O_TRUNC, 0700); | ||||
if (kdata_fd < 0) { | if (kdata_fd < 0) { | ||||
Show All 34 Lines | vm_checkpoint(struct vmctx *ctx, char *checkpoint_file, cap_channel_t *chn, bool stop_vm) | ||||
vm_vcpu_pause(ctx); | vm_vcpu_pause(ctx); | ||||
ret = vm_pause_user_devs(ctx); | ret = vm_pause_user_devs(ctx); | ||||
if (ret != 0) { | if (ret != 0) { | ||||
fprintf(stderr, "Could not pause devices\r\n"); | fprintf(stderr, "Could not pause devices\r\n"); | ||||
error = ret; | error = ret; | ||||
goto done; | goto done; | ||||
#ifndef WITHOUT_CAPSICUM | |||||
if (cdir_fd > 0) | if (cdir_fd > 0) | ||||
close(cdir_fd);} | close(cdir_fd); | ||||
#endif | |||||
} | |||||
memsz = vm_snapshot_mem(ctx, fd_checkpoint, 0, true); | memsz = vm_snapshot_mem(ctx, fd_checkpoint, 0, true); | ||||
if (memsz == 0) { | if (memsz == 0) { | ||||
perror("Could not write guest memory to file"); | perror("Could not write guest memory to file"); | ||||
error = -1; | error = -1; | ||||
goto done; | goto done; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | done: | ||||
if (kdata_filename != NULL) | if (kdata_filename != NULL) | ||||
free(kdata_filename); | free(kdata_filename); | ||||
if (xop != NULL) | if (xop != NULL) | ||||
xo_destroy(xop); | xo_destroy(xop); | ||||
if (meta_file != NULL) | if (meta_file != NULL) | ||||
fclose(meta_file); | fclose(meta_file); | ||||
if (kdata_fd > 0) | if (kdata_fd > 0) | ||||
close(kdata_fd); | close(kdata_fd); | ||||
#ifndef WITHOUT_CAPSICUM | |||||
if (cdir_fd > 0) | if (cdir_fd > 0) | ||||
close(cdir_fd); | close(cdir_fd); | ||||
#endif | |||||
return (error); | return (error); | ||||
} | } | ||||
int | int | ||||
handle_message(struct vmctx *ctx, nvlist_t *nvl, cap_channel_t *chn) | handle_message(struct vmctx *ctx, nvlist_t *nvl, cap_channel_t *chn) | ||||
{ | { | ||||
int err; | int err; | ||||
const char *cmd; | const char *cmd; | ||||
▲ Show 20 Lines • Show All 87 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Create the listening socket for IPC with bhyvectl | * Create the listening socket for IPC with bhyvectl | ||||
*/ | */ | ||||
int | int | ||||
init_checkpoint_thread(struct vmctx *ctx, cap_channel_t *chn) | init_checkpoint_thread(struct vmctx *ctx, char *ckp_path, cap_channel_t *chn) | ||||
{ | { | ||||
struct checkpoint_thread_info *checkpoint_info = NULL; | struct checkpoint_thread_info *checkpoint_info = NULL; | ||||
struct sockaddr_un addr; | struct sockaddr_un addr; | ||||
int socket_fd; | int socket_fd; | ||||
pthread_t checkpoint_pthread; | pthread_t checkpoint_pthread; | ||||
char vmname_buf[MAX_VMNAME]; | char vmname_buf[MAX_VMNAME]; | ||||
int ret, err = 0; | int ret, err = 0; | ||||
char *cdir_name; | |||||
memset(&addr, 0, sizeof(addr)); | memset(&addr, 0, sizeof(addr)); | ||||
socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0); | socket_fd = socket(PF_UNIX, SOCK_DGRAM, 0); | ||||
if (socket_fd < 0) { | if (socket_fd < 0) { | ||||
EPRINTLN("Socket creation failed: %s", strerror(errno)); | EPRINTLN("Socket creation failed: %s", strerror(errno)); | ||||
err = -1; | err = -1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
cdir_name = getcwd(NULL, 0); | if (ckp_path != NULL) { | ||||
cdir_fd = open(cdir_name, O_RDONLY | O_DIRECTORY); | cdir_fd = open(ckp_path, O_RDONLY | O_DIRECTORY); | ||||
if (cdir_fd < 0) { | if (cdir_fd < 0) { | ||||
perror("Failed to open working directory."); | perror("Failed to open working directory."); | ||||
err = -1; | err = -1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
free(cdir_name); | |||||
#ifndef WITHOUT_CAPSICUM | |||||
limit_control_socket(socket_fd); | limit_control_socket(socket_fd); | ||||
limit_file_operations(); | limit_file_operations(); | ||||
#endif | } | ||||
addr.sun_family = AF_UNIX; | addr.sun_family = AF_UNIX; | ||||
err = vm_get_name(ctx, vmname_buf, MAX_VMNAME - 1); | err = vm_get_name(ctx, vmname_buf, MAX_VMNAME - 1); | ||||
if (err != 0) { | if (err != 0) { | ||||
perror("Failed to get VM name"); | perror("Failed to get VM name"); | ||||
goto fail; | goto fail; | ||||
} | } | ||||
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s%s", | snprintf(addr.sun_path, sizeof(addr.sun_path), "%s%s", | ||||
BHYVE_RUN_DIR, vmname_buf); | BHYVE_RUN_DIR, vmname_buf); | ||||
addr.sun_len = SUN_LEN(&addr); | addr.sun_len = SUN_LEN(&addr); | ||||
unlink(addr.sun_path); | unlink(addr.sun_path); | ||||
if (bind(socket_fd, (struct sockaddr *)&addr, addr.sun_len) != 0) { | if (bind(socket_fd, (struct sockaddr *)&addr, addr.sun_len) != 0) { | ||||
EPRINTLN("Failed to bind socket \"%s\": %s\n", | EPRINTLN("Failed to bind socket \"%s\": %s\n", | ||||
addr.sun_path, strerror(errno)); | addr.sun_path, strerror(errno)); | ||||
err = -1; | err = -1; | ||||
goto fail; | goto fail; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 152 Lines • Show Last 20 Lines |