Enable time traveling ckpt
This commit is contained in:
parent
3cb6b6fabf
commit
997aa9edd8
|
@ -18,6 +18,7 @@
|
|||
#include <mm/vmspace.h>
|
||||
#include <common/vars.h>
|
||||
#include <sched/fpu.h>
|
||||
#include <mm/nvm.h>
|
||||
|
||||
/* idt and idtr */
|
||||
struct gate_desc idt[T_NUM] __attribute__((aligned(16)));
|
||||
|
@ -170,14 +171,10 @@ void handle_reset_sched(u32 cpuid)
|
|||
|
||||
void handle_wait_in_kernel(u32 cpuid) {
|
||||
save_fpu_state(current_thread);
|
||||
// struct thread *fpu_owner = (struct thread *)(cpu_info[cpuid].fpu_owner);
|
||||
// if(fpu_owner != NULL) {
|
||||
// save_fpu_state(fpu_owner);
|
||||
// }
|
||||
|
||||
/* Save FS for thread from */
|
||||
if (likely((current_thread) &&
|
||||
(current_thread->thread_ctx->type > TYPE_KERNEL))) {
|
||||
|
||||
current_thread->thread_ctx->tls_base_reg[TLS_FS] = __builtin_ia32_rdfsbase64();
|
||||
}
|
||||
mark_in_kernel_ipi_tx(cpuid);
|
||||
|
@ -211,6 +208,15 @@ void handle_irq(int irqno)
|
|||
// kinfo("CPU %d: receive IPI on TLB.\n", smp_get_cpu_id());
|
||||
handle_ipi();
|
||||
arch_ack_irq();
|
||||
/* re-schedule if restored */
|
||||
if (current_resched_flag == true) {
|
||||
current_resched_flag = false;
|
||||
sched();
|
||||
eret_to_thread(switch_context());
|
||||
|
||||
/* should never return */
|
||||
BUG_ON(1);
|
||||
}
|
||||
return;
|
||||
case IRQ_IPI_RESET_SCHED:
|
||||
handle_ipi();
|
||||
|
|
|
@ -36,9 +36,14 @@ struct xsave_area {
|
|||
|
||||
#define STATE_AREA_SIZE (sizeof(struct xsave_area))
|
||||
|
||||
u64 get_fpu_state_size()
|
||||
{
|
||||
return STATE_AREA_SIZE;
|
||||
}
|
||||
|
||||
void *alloc_fpu_state()
|
||||
{
|
||||
return kzalloc(STATE_AREA_SIZE);
|
||||
return kzalloc(get_fpu_state_size());
|
||||
}
|
||||
|
||||
#if USE_INSTRUCTION == USE_XSAVEOPT
|
||||
|
@ -47,7 +52,7 @@ void arch_init_thread_fpu(struct thread_ctx *ctx)
|
|||
struct xsave_area *area;
|
||||
|
||||
/* should be aligned to 64 */
|
||||
ctx->fpu_state = (void *)kzalloc(STATE_AREA_SIZE);
|
||||
ctx->fpu_state = alloc_fpu_state();
|
||||
ctx->is_fpu_owner = -1;
|
||||
|
||||
area = (struct xsave_area *)ctx->fpu_state;
|
||||
|
@ -65,7 +70,7 @@ void arch_init_thread_fpu(struct thread_ctx *ctx)
|
|||
void arch_init_thread_fpu(struct thread_ctx *ctx)
|
||||
{
|
||||
/* should be aligned to 64 */
|
||||
ctx->fpu_state = (void *)kzalloc(STATE_AREA_SIZE);
|
||||
ctx->fpu_state = alloc_fpu_state();
|
||||
ctx->is_fpu_owner = -1;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@ target_sources(${kernel_target}
|
|||
PRIVATE ckpt.c
|
||||
restore.c
|
||||
ckpt_ipi.c
|
||||
ckpt_time_traveling.c
|
||||
ckpt_ws.c
|
||||
ckpt_object_pool.c
|
||||
ckpt_page.c
|
||||
|
|
|
@ -139,14 +139,19 @@ int sys_whole_ckpt(u64 ckpt_name, u64 name_len)
|
|||
#endif
|
||||
finish_process_active_list();
|
||||
#endif
|
||||
r = ckpt_ws_put(data, ckpt_name, name_len);
|
||||
if (!r) {
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
/* TODO(MOK): remove the following two lines*/
|
||||
second_latest_ws_data = latest_ws_data;
|
||||
latest_ws_data = data;
|
||||
|
||||
/* issue an async copy */
|
||||
if (ckpt_name && name_len) {
|
||||
init_async_copying_task(data->ckpt_root_obj_root,
|
||||
ckpt_name,
|
||||
name_len,
|
||||
get_current_ckpt_version() - 1);
|
||||
}
|
||||
|
||||
smp_mb();
|
||||
|
||||
sys_ipi_start_all();
|
||||
|
@ -243,7 +248,7 @@ int sys_whole_ckpt_for_test(u64 ckpt_name, u64 name_len, u64 log_level)
|
|||
#ifdef REPORT
|
||||
u64 wait_migrate_finish = plat_get_mono_time() - timer_start - recycle_time - ipi_time - object_time - fmap_time;
|
||||
#endif
|
||||
r = ckpt_ws_put(data, ckpt_name, name_len);
|
||||
r = ckpt_ws_put_from_userspace(data, ckpt_name, name_len);
|
||||
if (!r) {
|
||||
goto out_fail;
|
||||
}
|
||||
|
|
|
@ -25,6 +25,16 @@ const obj_restore_func obj_restore_tbl[TYPE_NR] = {
|
|||
[TYPE_VMSPACE] = vmspace_restore,
|
||||
};
|
||||
|
||||
struct ckpt_ws_data *init_ckpt_ws_data()
|
||||
{
|
||||
struct ckpt_ws_data *data;
|
||||
data = kzalloc(sizeof(*data));
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
struct ckpt_ws_data *get_ckpt_ws_data()
|
||||
{
|
||||
struct ckpt_ws_data *data;
|
||||
|
@ -35,7 +45,7 @@ struct ckpt_ws_data *get_ckpt_ws_data()
|
|||
/* update data version number */
|
||||
data->version_number = data->version_number + 2;
|
||||
} else {
|
||||
data = kzalloc(sizeof(*data));
|
||||
data = init_ckpt_ws_data();
|
||||
if (!data) {
|
||||
goto out_fail;
|
||||
}
|
||||
|
@ -98,6 +108,24 @@ struct ckpt_object *ckpt_obj_alloc(u64 type)
|
|||
return object;
|
||||
}
|
||||
|
||||
struct ckpt_obj_root *ckpt_obj_root_alloc()
|
||||
{
|
||||
struct ckpt_obj_root *root;
|
||||
root = kmalloc(sizeof(*root));
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
#if OBJ_OVERWRITE == 1
|
||||
root->ckpt_objs[0] = NULL;
|
||||
root->ckpt_objs[1] = NULL;
|
||||
#endif
|
||||
root->cow = false;
|
||||
root->refcnt = 0;
|
||||
root->flip_flag = system_current_flip_flag ^ 1;
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
struct ckpt_obj_root *ckpt_obj_root_get(struct object *obj, int alloc)
|
||||
{
|
||||
if (!CKPT_GLOBAL_OBJ_MAP || !obj) {
|
||||
|
@ -107,19 +135,9 @@ struct ckpt_obj_root *ckpt_obj_root_get(struct object *obj, int alloc)
|
|||
|
||||
struct ckpt_obj_root *root = obj->obj_root;
|
||||
if (!root && alloc) {
|
||||
root = kmalloc(sizeof(*root));
|
||||
if (!root)
|
||||
return NULL;
|
||||
|
||||
root->obj = obj;
|
||||
#if OBJ_OVERWRITE == 1
|
||||
root->ckpt_objs[0] = NULL;
|
||||
root->ckpt_objs[1] = NULL;
|
||||
#endif
|
||||
root->cow = false;
|
||||
root->refcnt = 0;
|
||||
root->flip_flag = system_current_flip_flag ^ 1;
|
||||
root = ckpt_obj_root_alloc();
|
||||
obj->obj_root = root;
|
||||
root->obj = obj;
|
||||
}
|
||||
|
||||
return root;
|
||||
|
@ -299,19 +317,31 @@ struct object *restore_obj_get_by_cap_group(struct ckpt_obj_root *ckpt_obj_root,
|
|||
} else if (alloc) {
|
||||
ckpt_obj_root->flip_flag = system_current_flip_flag;
|
||||
|
||||
ckpt_obj = get_second_latest_ckpt_obj(
|
||||
ckpt_obj_root, get_current_ckpt_version());
|
||||
/* get ckpt obj */
|
||||
if (ckpt_obj_root->time_traveling) {
|
||||
/* time traveling obj always use the first ckpt_obj */
|
||||
ckpt_obj = ckpt_obj_root->ckpt_objs[0];
|
||||
} else {
|
||||
ckpt_obj = get_second_latest_ckpt_obj(
|
||||
ckpt_obj_root,
|
||||
get_current_ckpt_version());
|
||||
}
|
||||
BUG_ON(!ckpt_obj);
|
||||
obj = ckpt_obj_root->obj;
|
||||
|
||||
/* mark obj as restored */
|
||||
kvs_put(obj_map, (kvs_key_t *)&ckpt_obj_root,
|
||||
(kvs_value_t *)(&obj));
|
||||
|
||||
#ifdef RESTORE_REPORT
|
||||
DECLTMR;
|
||||
start();
|
||||
#endif
|
||||
/* Invoke the object-specific restore routine */
|
||||
// printk("restore type %d\n", obj->type);
|
||||
func = obj_restore_tbl[obj->type];
|
||||
if (func) {
|
||||
BUG_ON(func(obj, ckpt_obj, obj_map));
|
||||
BUG_ON(func(obj, ckpt_obj, obj_map, ckpt_obj_root->time_traveling));
|
||||
} else {
|
||||
WARN("obj restore func is NULL");
|
||||
BUG_ON(1);
|
||||
|
|
|
@ -14,8 +14,11 @@ struct object *restore_obj_get(struct ckpt_obj_root *ckpt_obj_root);
|
|||
|
||||
struct object *restore_obj_get_by_cap_group(struct ckpt_obj_root *ckpt_obj_root, struct kvs *obj_map,int alloc);
|
||||
|
||||
struct ckpt_obj_root *ckpt_obj_root_alloc();
|
||||
struct ckpt_obj_root *ckpt_obj_root_get(struct object *obj, int alloc);
|
||||
|
||||
struct ckpt_obj_root *get_copied_obj_root(struct ckpt_obj_root *ckpt_obj_root, struct kvs *obj_map);
|
||||
|
||||
struct ckpt_object *get_latest_ckpt_obj(struct ckpt_obj_root *ckpt_obj_root, u64 version_number);
|
||||
|
||||
struct ckpt_object *get_second_latest_ckpt_obj(struct ckpt_obj_root *ckpt_obj_root, u64 version_number);
|
||||
|
|
|
@ -20,28 +20,49 @@
|
|||
#include <ckpt/hot_pages_tracker.h>
|
||||
|
||||
/* Copy policy */
|
||||
int cap_group_copy_ckpt(struct cap_group *cap_group, struct ckpt_cap_group *ckpt_cap_group);
|
||||
int cap_group_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
int cap_group_copy_ckpt(struct cap_group *cap_group,
|
||||
struct ckpt_cap_group *ckpt_cap_group);
|
||||
int cap_group_restore(struct object *, struct ckpt_object *,
|
||||
struct kvs *obj_map, bool time_traveling);
|
||||
int ckpt_cap_group_copy(struct ckpt_object *src_obj,
|
||||
struct ckpt_object *dst_obj, struct kvs *);
|
||||
|
||||
int thread_ckpt(struct thread *target, struct ckpt_thread *ckpt_thread);
|
||||
int thread_restore(struct object *, struct ckpt_object *, struct kvs *obj_map,
|
||||
bool time_traveling);
|
||||
int ckpt_thread_copy(struct ckpt_object *src, struct ckpt_object *dst,
|
||||
struct kvs *);
|
||||
|
||||
int thread_ckpt(struct thread *target,struct ckpt_thread *ckpt_thread);
|
||||
int thread_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
int vmspace_ckpt(struct vmspace *target_vmspace,
|
||||
struct ckpt_vmspace *ckpt_vmspace);
|
||||
int vmspace_restore(struct object *, struct ckpt_object *, struct kvs *obj_map,
|
||||
bool time_traveling);
|
||||
int ckpt_vmspace_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj,
|
||||
struct kvs *obj_map);
|
||||
|
||||
int connection_ckpt(struct ipc_connection *conn,
|
||||
struct ckpt_ipc_connection *ckpt_conn, int alloc);
|
||||
int connection_restore(struct object *, struct ckpt_object *,
|
||||
struct kvs *obj_map, bool time_traveling);
|
||||
int ckpt_connection_copy(struct ckpt_object *src_obj,
|
||||
struct ckpt_object *dst_obj, struct kvs *obj_map);
|
||||
|
||||
int vmspace_ckpt(struct vmspace *target_vmspace, struct ckpt_vmspace *ckpt_vmspace);
|
||||
int vmspace_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
|
||||
int connection_ckpt(struct ipc_connection *conn,struct ckpt_ipc_connection *ckpt_conn, int alloc);
|
||||
int connection_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
|
||||
|
||||
int notification_ckpt(struct notification *notifc, struct ckpt_notification *ckpt_notifc, int alloc);
|
||||
int notification_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
|
||||
|
||||
int irq_ckpt(struct irq_notification *irq_notifc, struct ckpt_irq_notification *ckpt_irq_notifc, int alloc);
|
||||
int irq_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
int notification_ckpt(struct notification *notifc,
|
||||
struct ckpt_notification *ckpt_notifc, int alloc);
|
||||
int notification_restore(struct object *, struct ckpt_object *,
|
||||
struct kvs *obj_map, bool time_traveling);
|
||||
int ckpt_notification_copy(struct ckpt_object *src_obj,
|
||||
struct ckpt_object *dst_obj, struct kvs *obj_map);
|
||||
|
||||
int irq_ckpt(struct irq_notification *irq_notifc,
|
||||
struct ckpt_irq_notification *ckpt_irq_notifc, int alloc);
|
||||
int irq_restore(struct object *, struct ckpt_object *, struct kvs *obj_map,
|
||||
bool time_traveling);
|
||||
int ckpt_irq_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj,
|
||||
struct kvs *obj_map);
|
||||
|
||||
int pmo_ckpt(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo);
|
||||
int pmo_restore(struct object *, struct ckpt_object *, struct kvs* obj_map);
|
||||
int pmo_restore(struct object *, struct ckpt_object *, struct kvs *obj_map,
|
||||
bool time_traveling);
|
||||
int ckpt_pmo_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj,
|
||||
struct kvs *obj_map);
|
||||
|
|
|
@ -172,7 +172,8 @@ extern int cap_group_init(struct cap_group *cap_group, unsigned int size,
|
|||
u64 badge);
|
||||
int cap_group_restore(struct object *cap_group_obj,
|
||||
struct ckpt_object *ckpt_cap_group_obj,
|
||||
struct kvs *obj_map)
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
struct cap_group *cap_group = (struct cap_group *)cap_group_obj->opaque;
|
||||
struct ckpt_cap_group *ckpt_cap_group = (struct ckpt_cap_group *)ckpt_cap_group_obj->opaque;
|
||||
|
@ -191,3 +192,46 @@ int cap_group_restore(struct object *cap_group_obj,
|
|||
/* Restore slot table */
|
||||
return slot_table_restore(cap_group,ckpt_cap_group,obj_map);
|
||||
}
|
||||
|
||||
int ckpt_slot_table_copy(struct ckpt_object_slot *src_slots,
|
||||
struct ckpt_object_slot *dst_slots, int size,
|
||||
struct kvs *obj_map)
|
||||
{
|
||||
int i;
|
||||
struct ckpt_obj_root *copied_obj_root;
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
copied_obj_root =
|
||||
get_copied_obj_root(src_slots[i].obj_root, obj_map);
|
||||
BUG_ON(!copied_obj_root);
|
||||
|
||||
dst_slots[i].slot_id = src_slots[i].slot_id;
|
||||
dst_slots[i].obj_root = copied_obj_root;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ckpt_cap_group_copy(struct ckpt_object *src_obj,
|
||||
struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_cap_group *src_cap_group, *dst_cap_group;
|
||||
src_cap_group = (struct ckpt_cap_group *)src_obj->opaque;
|
||||
dst_cap_group = (struct ckpt_cap_group *)dst_obj->opaque;
|
||||
|
||||
/* Copy the contents of src_cap_group to dst_cap_group */
|
||||
memcpy(dst_cap_group, src_cap_group, sizeof(struct ckpt_cap_group));
|
||||
dst_cap_group->slots = (struct ckpt_object_slot *)kmalloc(
|
||||
(dst_cap_group->table_size) * sizeof(struct ckpt_object_slot));
|
||||
|
||||
kinfo("copy cap group: size %u (%u), badge %lx, name %s\n",
|
||||
dst_cap_group->table_size,
|
||||
src_cap_group->table_size,
|
||||
dst_cap_group->badge,
|
||||
dst_cap_group->cap_group_name);
|
||||
|
||||
/* Copy slot table */
|
||||
return ckpt_slot_table_copy(src_cap_group->slots,
|
||||
dst_cap_group->slots,
|
||||
src_cap_group->table_size,
|
||||
obj_map);
|
||||
}
|
||||
|
|
|
@ -50,7 +50,10 @@ out_fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
int connection_restore(struct object *conn_obj, struct ckpt_object *ckpt_conn_obj, struct kvs *obj_map)
|
||||
int connection_restore(struct object *conn_obj,
|
||||
struct ckpt_object *ckpt_conn_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
int r;
|
||||
struct ipc_connection *conn = (struct ipc_connection *)conn_obj->opaque;
|
||||
|
@ -91,3 +94,32 @@ int connection_restore(struct object *conn_obj, struct ckpt_object *ckpt_conn_ob
|
|||
out_fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
int ckpt_connection_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_ipc_connection *src, *dst;
|
||||
src = (struct ckpt_ipc_connection *)src_obj->opaque;
|
||||
dst = (struct ckpt_ipc_connection *)dst_obj->opaque;
|
||||
|
||||
/* Copy the contents of src to dst */
|
||||
memcpy(dst, src, sizeof(struct ckpt_ipc_connection));
|
||||
|
||||
/* Update the object roots using the object map */
|
||||
if (src->current_client_thread_root) {
|
||||
dst->current_client_thread_root = get_copied_obj_root(
|
||||
src->current_client_thread_root, obj_map);
|
||||
if (!dst->current_client_thread_root) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
if (src->server_handler_thread_root) {
|
||||
dst->server_handler_thread_root = get_copied_obj_root(
|
||||
src->server_handler_thread_root, obj_map);
|
||||
if (!dst->server_handler_thread_root) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,10 @@ int irq_ckpt(struct irq_notification *irq_notifc, struct ckpt_irq_notification *
|
|||
return notification_ckpt(&irq_notifc->notifc,&ckpt_irq_notifc->notifc, alloc);
|
||||
}
|
||||
|
||||
int irq_restore(struct object *irq_obj, struct ckpt_object *ckpt_irq_obj, struct kvs *obj_map)
|
||||
int irq_restore(struct object *irq_obj,
|
||||
struct ckpt_object *ckpt_irq_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
int i, r;
|
||||
struct irq_notification *irq_notifc = (struct irq_notification *)irq_obj->opaque;
|
||||
|
@ -50,3 +53,29 @@ int irq_restore(struct object *irq_obj, struct ckpt_object *ckpt_irq_obj, struct
|
|||
out_fail:
|
||||
return r;
|
||||
}
|
||||
|
||||
int ckpt_irq_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_irq_notification *src_irq, *dst_irq;
|
||||
int r;
|
||||
|
||||
src_irq = (struct ckpt_irq_notification *)src_obj->opaque;
|
||||
dst_irq = (struct ckpt_irq_notification *)dst_obj->opaque;
|
||||
|
||||
/* Copy basic fields */
|
||||
dst_irq->intr_vector = src_irq->intr_vector;
|
||||
dst_irq->status = src_irq->status;
|
||||
dst_irq->user_handler_ready = src_irq->user_handler_ready;
|
||||
|
||||
/* Copy the notification part */
|
||||
r = ckpt_notification_copy(
|
||||
(struct ckpt_object *)&src_irq->notifc,
|
||||
(struct ckpt_object *)&dst_irq->notifc,
|
||||
obj_map
|
||||
);
|
||||
if (r) {
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,10 @@ out_fail:
|
|||
return r;
|
||||
}
|
||||
|
||||
int notification_restore(struct object *notifc_obj, struct ckpt_object *ckpt_notifc_obj, struct kvs *obj_map)
|
||||
int notification_restore(struct object *notifc_obj,
|
||||
struct ckpt_object *ckpt_notifc_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
int r, i;
|
||||
struct notification *notifc = (struct notification *)notifc_obj->opaque;
|
||||
|
@ -76,4 +79,35 @@ int notification_restore(struct object *notifc_obj, struct ckpt_object *ckpt_not
|
|||
return 0;
|
||||
out_fail:
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
int ckpt_notification_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_notification *src, *dst;
|
||||
int i;
|
||||
|
||||
src = (struct ckpt_notification *)src_obj->opaque;
|
||||
dst = (struct ckpt_notification *)dst_obj->opaque;
|
||||
|
||||
/* Copy basic fields */
|
||||
dst->not_delivered_notifc_count = src->not_delivered_notifc_count;
|
||||
dst->waiting_threads_count = src->waiting_threads_count;
|
||||
dst->state = src->state;
|
||||
|
||||
/* Allocate memory for waiting_thread_roots */
|
||||
dst->waiting_thread_roots = kmalloc(src->waiting_threads_count * sizeof(struct ckpt_obj_root *));
|
||||
if (!dst->waiting_thread_roots) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Copy waiting thread roots */
|
||||
for (i = 0; i < src->waiting_threads_count; i++) {
|
||||
dst->waiting_thread_roots[i] = get_copied_obj_root(src->waiting_thread_roots[i], obj_map);
|
||||
if (!dst->waiting_thread_roots[i]) {
|
||||
kfree(dst->waiting_thread_roots);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "../ckpt_objects.h"
|
||||
#include "../ckpt_object_pool.h"
|
||||
#include "../ckpt_page.h"
|
||||
#include "../ckpt_ws.h"
|
||||
|
||||
extern int pgtbl_deep_copy(vaddr_t *src_pgtbl, vaddr_t *dst_pgtbl);
|
||||
|
||||
|
@ -304,7 +305,10 @@ int choose_nvm_ckpt_page_idx(struct ckpt_page_pair *page_pair)
|
|||
}
|
||||
}
|
||||
|
||||
static int __radix_pmo_restore(struct pmobject *pmo, struct radix_node *page_node, struct radix_node *ckpt_page_node, int node_level, u64 prefix)
|
||||
static int __radix_pmo_restore(struct pmobject *pmo,
|
||||
struct radix_node *page_node,
|
||||
struct radix_node *ckpt_page_node,
|
||||
int node_level, u64 prefix, bool time_traveling)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
|
@ -316,16 +320,37 @@ static int __radix_pmo_restore(struct pmobject *pmo, struct radix_node *page_nod
|
|||
|
||||
prefix <<= RADIX_NODE_BITS;
|
||||
|
||||
if(node_level == RADIX_LEVELS - 1) {
|
||||
for(i = 0;i < RADIX_NODE_SIZE;i++) {
|
||||
if((page_pair = ckpt_page_node->values[i]) || page_node->values[i]) {
|
||||
if (node_level == RADIX_LEVELS - 1) {
|
||||
for (i = 0;i < RADIX_NODE_SIZE;i++) {
|
||||
page_pair = ckpt_page_node->values[i];
|
||||
/* ckpt radix or runtime radix have value */
|
||||
if (page_pair || page_node->values[i]) {
|
||||
/* meta */
|
||||
pa = (paddr_t)page_node->values[i];
|
||||
BUG_ON(!pa);
|
||||
va = (vaddr_t)phys_to_virt(pa);
|
||||
/* set page info */
|
||||
struct page* page = virt_to_page((void*)va);
|
||||
page->track_info = NULL;
|
||||
page_type_t type = get_page_type(page);
|
||||
|
||||
/* set page info */
|
||||
page->track_info = NULL;
|
||||
|
||||
/* restore page */
|
||||
/* case 1: restore from time traveling */
|
||||
if (time_traveling) {
|
||||
/* use page_pair[0] to restore */
|
||||
if (page_pair) {
|
||||
pagecpy((void*)va, (void*)page_pair->pages[0].va);
|
||||
}
|
||||
/* clear runtime page */
|
||||
else if (!page_pair && va) {
|
||||
kfree((void*)va);
|
||||
page_node->values[i] = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* case 2: restore from normal NVM page */
|
||||
if (type == NVM_PAGE) {
|
||||
if (page_pair) {
|
||||
// int idx = choose_ckpt_page_idx(page_pair);
|
||||
|
@ -349,22 +374,20 @@ static int __radix_pmo_restore(struct pmobject *pmo, struct radix_node *page_nod
|
|||
}
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
}
|
||||
/* case 3: restore from normal DRAM page */
|
||||
else {
|
||||
BUG_ON(!page_pair);
|
||||
|
||||
int idx = choose_ckpt_page_idx(page_pair);
|
||||
int stale_idx = 1 - idx;
|
||||
|
||||
/* Use page_pair->pages[stale_idx] as runtime memory and page_pair->pages[idx] as backup */
|
||||
|
||||
/* Use page_pair->pages[stale_idx] as runtime memory */
|
||||
/* Use page_pair->pages[idx] as backup */
|
||||
BUG_ON(page_pair->pages[idx].version_number == 0);
|
||||
|
||||
va = page_pair->pages[stale_idx].va;
|
||||
|
||||
clear_ckpt_page(page_pair, stale_idx);
|
||||
|
||||
pagecpy((void*)va, (void*)page_pair->pages[idx].va);
|
||||
|
||||
page_node->values[i] = (void*)virt_to_phys((void*)va);
|
||||
|
||||
struct page *page = virt_to_page((void*)va);
|
||||
|
@ -395,7 +418,8 @@ static int __radix_pmo_restore(struct pmobject *pmo, struct radix_node *page_nod
|
|||
page_node->children[i],
|
||||
ckpt_page_node->children[i],
|
||||
node_level + 1,
|
||||
prefix | i);
|
||||
prefix | i,
|
||||
time_traveling);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -404,7 +428,7 @@ static int __radix_pmo_restore(struct pmobject *pmo, struct radix_node *page_nod
|
|||
return 0;
|
||||
}
|
||||
|
||||
int radix_pmo_restore(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo)
|
||||
int radix_pmo_restore(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo, bool time_traveling)
|
||||
{
|
||||
int r = 0;
|
||||
struct radix *pmo_radix = pmo->radix;
|
||||
|
@ -428,46 +452,82 @@ int radix_pmo_restore(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo)
|
|||
}
|
||||
pmo_radix->root = new_node;
|
||||
}
|
||||
r = __radix_pmo_restore(pmo, pmo_radix->root, ckpt_page_radix->root, 0, 0);
|
||||
unlock(&ckpt_page_radix->radix_lock);
|
||||
r = __radix_pmo_restore(pmo,
|
||||
pmo_radix->root,
|
||||
ckpt_page_radix->root,
|
||||
0,
|
||||
0,
|
||||
time_traveling);
|
||||
unlock(&ckpt_page_radix->radix_lock);
|
||||
unlock(&pmo_radix->radix_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __continuous_pmo_restore(struct pmobject *pmo, struct radix_node *ckpt_page_node, int node_level, u64 prefix)
|
||||
static int __continuous_pmo_restore(struct pmobject *pmo,
|
||||
struct radix_node *ckpt_page_node,
|
||||
int node_level, u64 prefix,
|
||||
bool time_traveling)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
int err, i, idx, stale_idx;
|
||||
struct ckpt_page_pair *page_pair;
|
||||
paddr_t pa;
|
||||
vaddr_t va;
|
||||
u64 index;
|
||||
u64 current_version = get_current_ckpt_version();
|
||||
|
||||
struct page *page;
|
||||
|
||||
prefix <<= RADIX_NODE_BITS;
|
||||
|
||||
if (node_level == RADIX_LEVELS - 1) {
|
||||
for (i = 0;i < RADIX_NODE_SIZE;i++) {
|
||||
if ((page_pair = ckpt_page_node->values[i])) {
|
||||
page_pair = ckpt_page_node->values[i];
|
||||
if (page_pair) {
|
||||
index = prefix | i;
|
||||
|
||||
/* meta */
|
||||
pa = (paddr_t)(pmo->start + index * PAGE_SIZE);
|
||||
va = (vaddr_t)phys_to_virt(pa);
|
||||
/* set page info */
|
||||
struct page* page = virt_to_page((void*)va);
|
||||
page->track_info = NULL;
|
||||
page = virt_to_page((void*)va);
|
||||
|
||||
int idx = choose_ckpt_page_idx(page_pair);
|
||||
int stale_idx = 1 - idx;
|
||||
/* set page info */
|
||||
page->track_info = NULL;
|
||||
|
||||
/**
|
||||
* case 1: time traveling
|
||||
* always use the first page to restore
|
||||
*/
|
||||
if (time_traveling) {
|
||||
pagecpy((void*)va, (void*)page_pair->pages[0].va);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* case 2: non-time traveling */
|
||||
idx = choose_ckpt_page_idx(page_pair);
|
||||
stale_idx = 1 - idx;
|
||||
clear_ckpt_page(page_pair, stale_idx);
|
||||
/* use dram_cache to know page type */
|
||||
if (pmo->dram_cache.array == NULL || pmo->dram_cache.array[index] == 0) {
|
||||
/* page type == NVM */
|
||||
/**
|
||||
* case 2.1: page type == NVM
|
||||
* Figure 6(a): va is the newest page unless
|
||||
* page_pair->pages[idx].version_number == current_version
|
||||
*/
|
||||
BUG_ON(page_pair->pages[stale_idx].va == page_pair->pages[idx].va);
|
||||
BUG_ON(va == page_pair->pages[idx].va || va != page_pair->pages[stale_idx].va);
|
||||
BUG_ON(va == page_pair->pages[idx].va ||
|
||||
va != page_pair->pages[stale_idx].va);
|
||||
if (page_pair->pages[idx].version_number == current_version) {
|
||||
pagecpy((void*)va, (void*)page_pair->pages[idx].va);
|
||||
}
|
||||
} else {
|
||||
pagecpy((void*)page_pair->pages[stale_idx].va, (void*)page_pair->pages[idx].va);
|
||||
/**
|
||||
* case 2.2: page type == DRAM
|
||||
* this page must be checkpointed, page_pair has the newest page
|
||||
* Figure 6(b) DRAM-to-NVM:
|
||||
* 1. copy two page_pair as the same
|
||||
* 2. clear the stale page
|
||||
*/
|
||||
pagecpy((void*)page_pair->pages[stale_idx].va,
|
||||
(void*)page_pair->pages[idx].va);
|
||||
if (va == page_pair->pages[idx].va) {
|
||||
page_pair->pages[stale_idx].version_number = current_version;
|
||||
clear_ckpt_page(page_pair, idx);
|
||||
|
@ -483,7 +543,8 @@ static int __continuous_pmo_restore(struct pmobject *pmo, struct radix_node *ckp
|
|||
err = __continuous_pmo_restore(pmo,
|
||||
ckpt_page_node->children[i],
|
||||
node_level + 1,
|
||||
prefix | i);
|
||||
prefix | i,
|
||||
time_traveling);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
@ -492,7 +553,7 @@ static int __continuous_pmo_restore(struct pmobject *pmo, struct radix_node *ckp
|
|||
return 0;
|
||||
}
|
||||
|
||||
int continuous_pmo_restore(struct pmobject *pmo, struct radix *ckpt_page_radix)
|
||||
int continuous_pmo_restore(struct pmobject *pmo, struct radix *ckpt_page_radix, bool time_traveling)
|
||||
{
|
||||
int r = 0;
|
||||
struct radix_node *new_node;
|
||||
|
@ -505,32 +566,36 @@ int continuous_pmo_restore(struct pmobject *pmo, struct radix *ckpt_page_radix)
|
|||
ckpt_page_radix->root = new_node;
|
||||
}
|
||||
|
||||
r = __continuous_pmo_restore(pmo, ckpt_page_radix->root, 0, 0);
|
||||
r = __continuous_pmo_restore(pmo, ckpt_page_radix->root, 0, 0, time_traveling);
|
||||
unlock(&ckpt_page_radix->radix_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
static int __init_ckpt_page_radix(struct radix_node *page_node, struct radix_node *ckpt_page_node, int node_level)
|
||||
static int __init_ckpt_page_radix(struct radix_node *page_node,
|
||||
struct radix_node *ckpt_page_node,
|
||||
int node_level)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
struct radix_node *new;
|
||||
struct page *page;
|
||||
struct ckpt_page_pair *page_pair;
|
||||
|
||||
if (node_level == RADIX_LEVELS - 1) {
|
||||
for (i = 0;i < RADIX_NODE_SIZE;i++) {
|
||||
if (page_node->values[i]) {
|
||||
struct ckpt_page_pair *page_pair = kzalloc(sizeof(*page_pair));
|
||||
page_pair = kzalloc(sizeof(*page_pair));
|
||||
if (!page_pair) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
// printk("%s: page=%p\n", __func__, virt_to_page((void*)phys_to_virt(page_node->values[i])));
|
||||
page_pair->pages[0].va = (vaddr_t)get_pages(0);
|
||||
page_pair->pages[1].va = phys_to_virt(page_node->values[i]);
|
||||
pagecpy((void*)page_pair->pages[0].va, (void*)phys_to_virt(page_node->values[i]));
|
||||
pagecpy((void *)page_pair->pages[0].va,
|
||||
(void *)phys_to_virt(page_node->values[i]));
|
||||
page_pair->pages[0].version_number = get_current_ckpt_version();
|
||||
ckpt_page_node->values[i] = page_pair;
|
||||
page = (struct page*)virt_to_page((void*)phys_to_virt(page_node->values[i]));
|
||||
page = (struct page *)virt_to_page(
|
||||
(void *)phys_to_virt(page_node->values[i]));
|
||||
page->page_pair = (u64)page_pair;
|
||||
}
|
||||
}
|
||||
|
@ -570,14 +635,10 @@ int init_ckpt_page_radix(struct ckpt_pmobject* ckpt_pmo, struct pmobject *pmo)
|
|||
ckpt_page_radix = ckpt_pmo->radix;
|
||||
|
||||
/* copy all pages in pmo to ckpt page in ckpt pmo*/
|
||||
if(use_radix(pmo)) {
|
||||
// lock(&pmo_radix->radix_lock);
|
||||
// lock(&ckpt_page_radix->radix_lock);
|
||||
if (use_radix(pmo)) {
|
||||
r = __init_ckpt_page_radix(pmo_radix->root,
|
||||
ckpt_page_radix->root,
|
||||
0);
|
||||
// unlock(&ckpt_page_radix->radix_lock);
|
||||
// unlock(&pmo_radix->radix_lock);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
@ -585,27 +646,27 @@ int init_ckpt_page_radix(struct ckpt_pmobject* ckpt_pmo, struct pmobject *pmo)
|
|||
|
||||
int pmo_ckpt(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo)
|
||||
{
|
||||
/*Step 1: init ckpt pmo */
|
||||
/* Step 1: init ckpt pmo */
|
||||
int r;
|
||||
u64 current_ckpt_version;
|
||||
u64 current_ckpt_version = get_current_ckpt_version();
|
||||
struct ckpt_obj_root *pmo_root;
|
||||
struct ckpt_object *latest_ckpt_obj;
|
||||
struct ckpt_pmobject *latest_ckpt_pmo;
|
||||
|
||||
ckpt_pmo->private = pmo->private;
|
||||
ckpt_pmo->size = pmo->size;
|
||||
ckpt_pmo->type = pmo->type;
|
||||
|
||||
current_ckpt_version = get_current_ckpt_version();
|
||||
|
||||
if (use_continuous_pages(pmo) || use_radix(pmo)) {
|
||||
if (unlikely(!ckpt_pmo->radix)) {
|
||||
/* If the radix tree is not created, try to reuse the
|
||||
* previous version of the radix tree */
|
||||
struct ckpt_obj_root *pmo_root;
|
||||
struct ckpt_object *latest_ckpt_obj;
|
||||
pmo_root = ckpt_obj_root_get(container_of(pmo, struct object,opaque), false);
|
||||
if (pmo_root && (latest_ckpt_obj =
|
||||
get_latest_ckpt_obj(pmo_root, current_ckpt_version))) {
|
||||
struct ckpt_pmobject *latest_ckpt_pmo =
|
||||
(struct ckpt_pmobject*)latest_ckpt_obj->opaque;
|
||||
pmo_root = ckpt_obj_root_get(container_of(pmo, struct object, opaque),
|
||||
false);
|
||||
latest_ckpt_obj = get_latest_ckpt_obj(pmo_root,
|
||||
current_ckpt_version);
|
||||
if (pmo_root && latest_ckpt_obj) {
|
||||
latest_ckpt_pmo = (struct ckpt_pmobject*)latest_ckpt_obj->opaque;
|
||||
BUG_ON(!latest_ckpt_pmo->radix);
|
||||
ckpt_pmo->radix = latest_ckpt_pmo->radix;
|
||||
} else {
|
||||
|
@ -646,7 +707,10 @@ int pmo_ckpt(struct pmobject *pmo, struct ckpt_pmobject *ckpt_pmo)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int pmo_restore(struct object *pmo_obj, struct ckpt_object *ckpt_pmo_obj, struct kvs* obj_map)
|
||||
int pmo_restore(struct object *pmo_obj,
|
||||
struct ckpt_object *ckpt_pmo_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
int r = 0;
|
||||
struct ckpt_pmobject *ckpt_pmo = (struct ckpt_pmobject *)ckpt_pmo_obj->opaque;
|
||||
|
@ -672,8 +736,11 @@ int pmo_restore(struct object *pmo_obj, struct ckpt_object *ckpt_pmo_obj, struct
|
|||
struct page *sp;
|
||||
|
||||
if (use_continuous_pages(pmo)) {
|
||||
continuous_pmo_restore(pmo, ckpt_pmo->radix);
|
||||
pmo->dram_cache.array = NULL;
|
||||
continuous_pmo_restore(pmo, ckpt_pmo->radix, time_traveling);
|
||||
/* clear dram cache */
|
||||
if (pmo->dram_cache.array) {
|
||||
clear_dram_cache(pmo);
|
||||
}
|
||||
lock_init(&pmo->dram_cache.lock);
|
||||
|
||||
pmo_start_va = phys_to_virt(pmo->start);
|
||||
|
@ -695,8 +762,7 @@ int pmo_restore(struct object *pmo_obj, struct ckpt_object *ckpt_pmo_obj, struct
|
|||
} else if (use_radix(pmo)) {
|
||||
/* restore radix tree */
|
||||
lock_init(&pmo->radix->radix_lock);
|
||||
r = radix_pmo_restore(pmo, ckpt_pmo);
|
||||
|
||||
r = radix_pmo_restore(pmo, ckpt_pmo, time_traveling);
|
||||
#ifdef PMO_CHECKSUM
|
||||
if (!is_external_sync_pmo(pmo)) {
|
||||
printk("[pmo %lx, type:%d]\n", pmo, pmo->type);
|
||||
|
@ -734,17 +800,15 @@ static int __radix_deep_copy_with_hybird_mem(struct radix_node *src, struct radi
|
|||
void *src_pa = src->values[i];
|
||||
void *src_va = (void*)phys_to_virt(src_pa);
|
||||
struct page *page = virt_to_page(src_va);
|
||||
if(get_page_type(page) == NVM_PAGE) {
|
||||
if (get_page_type(page) == NVM_PAGE) {
|
||||
lock(&page->lock);
|
||||
if(page->track_info) {
|
||||
if (page->track_info->active) {
|
||||
delete_from_active_list(page->track_info);
|
||||
}
|
||||
if (page->track_info && page->track_info->active) {
|
||||
delete_from_active_list(page->track_info);
|
||||
}
|
||||
atomic_fetch_add_64(&page->ref_cnt,1);
|
||||
atomic_fetch_add_64(&page->ref_cnt, 1);
|
||||
unlock(&page->lock);
|
||||
dst->values[i] = src_pa;
|
||||
}else {
|
||||
} else {
|
||||
void *newpage = get_pages(0);
|
||||
BUG_ON(!newpage);
|
||||
pagecpy(newpage,
|
||||
|
@ -803,4 +867,133 @@ int radix_deep_copy_with_hybird_mem(struct radix *src,struct radix *dst)
|
|||
out:
|
||||
unlock(&src->radix_lock);
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
static int __ckpt_radix_deep_copy(struct radix_node *src, struct radix_node *dst, u64 version_number, int node_level)
|
||||
{
|
||||
int err;
|
||||
int i;
|
||||
struct radix_node *new;
|
||||
struct ckpt_page_pair *src_page_pair, *dst_page_pair;
|
||||
struct ckpt_page *page;
|
||||
if (node_level == RADIX_LEVELS - 1) {
|
||||
for (i = 0; i < RADIX_NODE_SIZE; i++) {
|
||||
src_page_pair = src->values[i];
|
||||
if (src_page_pair) {
|
||||
page = get_ckpt_page_with_version(src_page_pair, version_number);
|
||||
/* get or alloc page's dst page pair */
|
||||
if (page->tt_page) {
|
||||
dst_page_pair = page->tt_page;
|
||||
dst_page_pair->refcnt++;
|
||||
} else {
|
||||
dst_page_pair = kzalloc(sizeof(struct ckpt_page_pair));
|
||||
dst_page_pair->type = CKPT_PP_TT;
|
||||
dst_page_pair->refcnt = 1;
|
||||
page->tt_page = dst_page_pair;
|
||||
}
|
||||
|
||||
/* copy according to type */
|
||||
if (src_page_pair->type == CKPT_PP_DRAM) {
|
||||
/* direct copt dram cached page */
|
||||
void *newpage = get_pages(0);
|
||||
BUG_ON(!newpage);
|
||||
pagecpy(newpage, (void *)page->va);
|
||||
dst_page_pair->pages[0].va = (u64)newpage;
|
||||
} else if (src_page_pair->type == CKPT_PP_NVM) {
|
||||
/* delay copy when page is modified */
|
||||
/* first use the same va with src ckpt page */
|
||||
dst_page_pair->pages[0].va = page->va;
|
||||
}
|
||||
|
||||
/* set dst page pair */
|
||||
dst->values[i] = dst_page_pair;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < RADIX_NODE_SIZE; i++) {
|
||||
if (src->children[i]) {
|
||||
new = kzalloc(sizeof(struct radix_node));
|
||||
if (IS_ERR(new)) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
dst->children[i] = new;
|
||||
err = __ckpt_radix_deep_copy(src->children[i],
|
||||
dst->children[i],
|
||||
version_number,
|
||||
node_level + 1);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ckpt_radix_deep_copy(struct radix *src, struct radix *dst, u64 version_number)
|
||||
{
|
||||
int r;
|
||||
struct radix_node *new;
|
||||
BUG_ON(!(src && dst));
|
||||
r = 0;
|
||||
|
||||
/* don't need to lock dst */
|
||||
lock(&src->radix_lock);
|
||||
|
||||
if (!src->root) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!dst->root) {
|
||||
new = kzalloc(sizeof(struct radix_node));
|
||||
if (IS_ERR(new)) {
|
||||
r = -ENOMEM;
|
||||
}
|
||||
dst->root = new;
|
||||
}
|
||||
|
||||
r = __ckpt_radix_deep_copy(src->root, dst->root, version_number, 0);
|
||||
out:
|
||||
unlock(&src->radix_lock);
|
||||
return r;
|
||||
}
|
||||
|
||||
int ckpt_pmo_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_pmobject *src_pmo, *dst_pmo;
|
||||
int r;
|
||||
|
||||
src_pmo = (struct ckpt_pmobject *)src_obj->opaque;
|
||||
dst_pmo = (struct ckpt_pmobject *)dst_obj->opaque;
|
||||
|
||||
/* Copy basic fields */
|
||||
dst_pmo->size = src_pmo->size;
|
||||
dst_pmo->start = src_pmo->start;
|
||||
dst_pmo->type = src_pmo->type;
|
||||
|
||||
/* Copy radix tree */
|
||||
if (src_pmo->radix) {
|
||||
/* init radix tree */
|
||||
dst_pmo->radix = kzalloc(sizeof(struct radix));
|
||||
if (!dst_pmo->radix) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
init_radix(dst_pmo->radix);
|
||||
|
||||
/* Deep copy the radix tree */
|
||||
r = ckpt_radix_deep_copy(src_pmo->radix,
|
||||
dst_pmo->radix,
|
||||
latest_node->version_number);
|
||||
if (r) {
|
||||
kfree(dst_pmo->radix);
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
dst_pmo->radix = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "../ckpt_objects.h"
|
||||
#include "../ckpt_object_pool.h"
|
||||
#include "../ckpt_ws.h"
|
||||
#include "common/kvstore.h"
|
||||
#include "sched/sched.h"
|
||||
|
||||
void* alloc_ckpt_ipc_config(int config_type)
|
||||
{
|
||||
|
@ -127,7 +130,63 @@ void ipc_config_ckpt(void* config, void* ckpt_config, int config_type)
|
|||
}
|
||||
}
|
||||
|
||||
int thread_ckpt(struct thread *target,struct ckpt_thread *ckpt_thread)
|
||||
void ckpt_ipc_config_copy(void* src_ipc_config, void* dst_ipc_config, int config_type, struct kvs *obj_map)
|
||||
{
|
||||
switch(config_type) {
|
||||
case IPC_SERVER_REGISTER_CB:{
|
||||
struct ckpt_ipc_server_register_cb_config *src =
|
||||
(struct ckpt_ipc_server_register_cb_config *)src_ipc_config;
|
||||
struct ckpt_ipc_server_register_cb_config *dst =
|
||||
(struct ckpt_ipc_server_register_cb_config *)dst_ipc_config;
|
||||
memcpy(dst, src, sizeof(struct ckpt_ipc_server_register_cb_config));
|
||||
break;
|
||||
}
|
||||
case IPC_SERVER_HANDLER:{
|
||||
struct ckpt_ipc_server_handler_config *src =
|
||||
(struct ckpt_ipc_server_handler_config *)src_ipc_config;
|
||||
struct ckpt_ipc_server_handler_config *dst =
|
||||
(struct ckpt_ipc_server_handler_config *)dst_ipc_config;
|
||||
struct ckpt_obj_root *ckpt_obj_root;
|
||||
|
||||
memcpy(dst, src, sizeof(struct ckpt_ipc_server_handler_config));
|
||||
|
||||
if (src->active_conn_root) {
|
||||
ckpt_obj_root = get_copied_obj_root(src->active_conn_root, obj_map);
|
||||
BUG_ON(ckpt_obj_root == NULL);
|
||||
dst->active_conn_root = ckpt_obj_root;
|
||||
} else {
|
||||
dst->active_conn_root = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case IPC_SERVER:{
|
||||
struct ckpt_ipc_server_config *src =
|
||||
(struct ckpt_ipc_server_config *)src_ipc_config;
|
||||
struct ckpt_ipc_server_config *dst =
|
||||
(struct ckpt_ipc_server_config *)dst_ipc_config;
|
||||
struct ckpt_obj_root *ckpt_thread_obj_root;
|
||||
|
||||
dst->config_type = src->config_type;
|
||||
dst->declared_ipc_routine_entry =
|
||||
src->declared_ipc_routine_entry;
|
||||
|
||||
if (src->register_cb_thread_root) {
|
||||
ckpt_thread_obj_root = get_copied_obj_root(src->register_cb_thread_root, obj_map);
|
||||
BUG_ON(ckpt_thread_obj_root == NULL);
|
||||
dst->register_cb_thread_root = ckpt_thread_obj_root;
|
||||
} else {
|
||||
dst->register_cb_thread_root = NULL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
int thread_ckpt(struct thread *target, struct ckpt_thread *ckpt_thread)
|
||||
{
|
||||
/* Copy thread_ctx data */
|
||||
thread_ctx_ckpt(&ckpt_thread->thread_ctx,target->thread_ctx);
|
||||
|
@ -142,11 +201,9 @@ int thread_ckpt(struct thread *target,struct ckpt_thread *ckpt_thread)
|
|||
|
||||
ckpt_config = (struct ipc_config *)ckpt_thread->general_ipc_config;
|
||||
if (!ckpt_config) {
|
||||
/* we can not reuse it if the pointer of config is NULL*/
|
||||
ckpt_config = alloc_ckpt_ipc_config(config_type);
|
||||
} else if (config_type
|
||||
!= ((struct ipc_config *)ckpt_thread->general_ipc_config)
|
||||
->config_type) {
|
||||
/* we can not reuse it if the pointer of config is NULL*/
|
||||
ckpt_config = alloc_ckpt_ipc_config(config_type);
|
||||
} else if (config_type != ((struct ipc_config *)ckpt_thread->general_ipc_config)->config_type) {
|
||||
/* we can not reuse it if the type of ipc config in checkpoint
|
||||
* is different from the target thread*/
|
||||
kfree(ckpt_config);
|
||||
|
@ -181,7 +238,7 @@ int thread_ckpt(struct thread *target,struct ckpt_thread *ckpt_thread)
|
|||
}
|
||||
|
||||
|
||||
static void thread_ctx_restore(struct ckpt_thread_ctx *ckpt_ctx,struct thread_ctx *target_ctx)
|
||||
static void thread_ctx_restore(struct ckpt_thread_ctx *ckpt_ctx, struct thread_ctx *target_ctx)
|
||||
{
|
||||
int i;
|
||||
BUG_ON(ckpt_ctx == NULL || target_ctx == NULL);
|
||||
|
@ -215,7 +272,9 @@ static void thread_ctx_restore(struct ckpt_thread_ctx *ckpt_ctx,struct thread_ct
|
|||
}
|
||||
}
|
||||
|
||||
void thread_sleep_state_restore(struct ckpt_sleep_state *ckpt_sleep_state, struct sleep_state *sleep_state, struct kvs *obj_map)
|
||||
void thread_sleep_state_restore(struct ckpt_sleep_state *ckpt_sleep_state,
|
||||
struct sleep_state *sleep_state,
|
||||
struct kvs *obj_map)
|
||||
{
|
||||
/* Copy fields */
|
||||
sleep_state->cb = ckpt_sleep_state->cb;
|
||||
|
@ -229,7 +288,10 @@ void thread_sleep_state_restore(struct ckpt_sleep_state *ckpt_sleep_state, struc
|
|||
lock_init(&sleep_state->queue_lock);
|
||||
}
|
||||
|
||||
int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_obj, struct kvs *obj_map)
|
||||
int thread_restore(struct object *thread_obj,
|
||||
struct ckpt_object *ckpt_thread_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
struct ckpt_thread *ckpt_thread = (struct ckpt_thread *)ckpt_thread_obj->opaque;
|
||||
struct thread *target = (struct thread *)thread_obj->opaque;
|
||||
|
@ -271,11 +333,11 @@ int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_ob
|
|||
new_config->ipc_routine_entry = ckpt_config->ipc_routine_entry;
|
||||
new_config->ipc_routine_stack = ckpt_config->ipc_routine_stack;
|
||||
new_config->ipc_lock = ckpt_config->ipc_lock;
|
||||
if(ckpt_config->active_conn_root) {
|
||||
if (ckpt_config->active_conn_root) {
|
||||
new_conn_obj = restore_obj_get(ckpt_config->active_conn_root);
|
||||
BUG_ON(new_conn_obj == NULL);
|
||||
new_config->active_conn = (struct ipc_connection*)new_conn_obj->opaque;
|
||||
}else {
|
||||
} else {
|
||||
new_config->active_conn = NULL;
|
||||
}
|
||||
|
||||
|
@ -303,7 +365,7 @@ int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_ob
|
|||
default:
|
||||
BUG_ON(1);
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
target->general_ipc_config = NULL;
|
||||
}
|
||||
|
||||
|
@ -318,12 +380,11 @@ int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_ob
|
|||
cap_obj = restore_obj_get(ckpt_thread->vmspace_root);
|
||||
BUG_ON(!cap_obj);
|
||||
struct vmspace* thread_vmspace = (struct vmspace*)cap_obj->opaque;
|
||||
// struct vmspace* thread_vmspace = obj_get(thread_cap_group,VMSPACE_OBJ_ID,TYPE_VMSPACE);
|
||||
// BUG_ON(!thread_vmspace);
|
||||
BUG_ON(!thread_vmspace);
|
||||
target->vmspace = thread_vmspace;
|
||||
// obj_put(thread_vmspace);
|
||||
kdebug("[Restore] restore thread %lx from %s, type=%u, rip=%lx, rsp=%lx, "
|
||||
"state=%u, cpuid=%u, kernel_stack_state=%u, id=%lx\n",
|
||||
|
||||
kdebug("[Restore] restore thread %lx from %s, type=%u, rip=%lx, rsp=%lx,\n"
|
||||
"\tstate=%u, cpuid=%u, kernel_stack_state=%u, id=%lx\n",
|
||||
target,
|
||||
thread_cap_group->cap_group_name,
|
||||
target->thread_ctx->type,
|
||||
|
@ -349,7 +410,6 @@ int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_ob
|
|||
case TS_RUNNING:
|
||||
case TS_READY:{
|
||||
target->thread_ctx->state = TS_INTER;
|
||||
// kinfo("thread %lx enqueue\n",target);
|
||||
BUG_ON(sched_enqueue(target));
|
||||
break;
|
||||
}
|
||||
|
@ -361,5 +421,55 @@ int thread_restore(struct object *thread_obj, struct ckpt_object *ckpt_thread_ob
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (target == current_thread) {
|
||||
target->thread_ctx->state = TS_RUNNING;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define STATE_AREA_SIZE (sizeof(struct xsave_area))
|
||||
|
||||
int ckpt_thread_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_thread *src = (struct ckpt_thread *)src_obj->opaque;
|
||||
struct ckpt_thread *dst = (struct ckpt_thread *)dst_obj->opaque;
|
||||
|
||||
/* Copy thread_ctx */
|
||||
memcpy(&dst->thread_ctx,
|
||||
&src->thread_ctx,
|
||||
sizeof(struct ckpt_thread_ctx));
|
||||
|
||||
/* Copt thread_ctx->fpu_state */
|
||||
dst->thread_ctx.fpu_state = alloc_fpu_state();
|
||||
memcpy(dst->thread_ctx.fpu_state,
|
||||
src->thread_ctx.fpu_state,
|
||||
get_fpu_state_size());
|
||||
|
||||
/* Copy sleep_state */
|
||||
memcpy(&dst->sleep_state,
|
||||
&src->sleep_state,
|
||||
sizeof(struct ckpt_sleep_state));
|
||||
|
||||
/* Copy cap_group_root and vmspace_root */
|
||||
dst->cap_group_root = get_copied_obj_root(src->cap_group_root, obj_map);
|
||||
dst->vmspace_root = get_copied_obj_root(src->vmspace_root, obj_map);
|
||||
|
||||
/* Copy general_ipc_config */
|
||||
if (src->general_ipc_config) {
|
||||
int config_type = ((struct ipc_config*)src->general_ipc_config)->config_type;
|
||||
dst->general_ipc_config = alloc_ckpt_ipc_config(config_type);
|
||||
if (!dst->general_ipc_config) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
ckpt_ipc_config_copy(src->general_ipc_config,
|
||||
dst->general_ipc_config,
|
||||
config_type,
|
||||
obj_map);
|
||||
} else {
|
||||
dst->general_ipc_config = NULL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -187,7 +187,10 @@ out_fail:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int vmspace_restore(struct object *vm_obj, struct ckpt_object *ckpt_vm_obj, struct kvs* obj_map)
|
||||
int vmspace_restore(struct object *vm_obj,
|
||||
struct ckpt_object *ckpt_vm_obj,
|
||||
struct kvs *obj_map,
|
||||
bool time_traveling)
|
||||
{
|
||||
int r;
|
||||
struct vmspace *target_vmspace = (struct vmspace *)vm_obj->opaque;
|
||||
|
@ -231,3 +234,45 @@ int vmspace_restore(struct object *vm_obj, struct ckpt_object *ckpt_vm_obj, stru
|
|||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
int ckpt_vmspace_copy(struct ckpt_object *src_obj, struct ckpt_object *dst_obj, struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_vmspace *src_vmspace, *dst_vmspace;
|
||||
int i, r;
|
||||
|
||||
src_vmspace = (struct ckpt_vmspace *)src_obj->opaque;
|
||||
dst_vmspace = (struct ckpt_vmspace *)dst_obj->opaque;
|
||||
|
||||
/* Copy basic fields */
|
||||
dst_vmspace->pcid = src_vmspace->pcid;
|
||||
dst_vmspace->user_current_mmap_addr = src_vmspace->user_current_mmap_addr;
|
||||
dst_vmspace->vmr_count = src_vmspace->vmr_count;
|
||||
dst_vmspace->heap_vmr_idx = src_vmspace->heap_vmr_idx;
|
||||
|
||||
/* Allocate memory for ckpt_vmrs */
|
||||
dst_vmspace->ckpt_vmrs = kmalloc(src_vmspace->vmr_count * sizeof(struct ckpt_vmregion));
|
||||
if (!dst_vmspace->ckpt_vmrs) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Copy each vmregion */
|
||||
for (i = 0; i < src_vmspace->vmr_count; i++) {
|
||||
memcpy(&dst_vmspace->ckpt_vmrs[i], &src_vmspace->ckpt_vmrs[i], sizeof(struct ckpt_vmregion));
|
||||
|
||||
/* Update the pmo_root using the object map */
|
||||
if (src_vmspace->ckpt_vmrs[i].pmo_root) {
|
||||
dst_vmspace->ckpt_vmrs[i].pmo_root = get_copied_obj_root(
|
||||
src_vmspace->ckpt_vmrs[i].pmo_root, obj_map);
|
||||
if (!dst_vmspace->ckpt_vmrs[i].pmo_root) {
|
||||
r = -ENOMEM;
|
||||
goto out_free_vmrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
out_free_vmrs:
|
||||
kfree(dst_vmspace->ckpt_vmrs);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#include <common/radix.h>
|
||||
#include "ckpt_page.h"
|
||||
#include <mm/mm.h>
|
||||
#include <mm/nvm.h>
|
||||
#include <common/list.h>
|
||||
|
||||
#include "ckpt_page.h"
|
||||
|
||||
/*
|
||||
* when the version number of page_0 and page_1 are equal,
|
||||
* we treat page_0 as the new one.
|
||||
|
@ -20,6 +21,19 @@ inline struct ckpt_page* get_second_latest_ckpt_page(struct ckpt_page_pair *page
|
|||
&page_pair->pages[1] : &page_pair->pages[0];
|
||||
}
|
||||
|
||||
inline struct ckpt_page* get_ckpt_page_with_version(struct ckpt_page_pair *page_pair, u64 version_number)
|
||||
{
|
||||
/* return the largest version less than @version_number */
|
||||
if (page_pair->pages[0].version_number <= version_number &&
|
||||
(page_pair->pages[1].version_number > version_number ||
|
||||
page_pair->pages[0].version_number > page_pair->pages[1].version_number)) {
|
||||
return &page_pair->pages[0];
|
||||
} else if (page_pair->pages[1].version_number <= version_number) {
|
||||
return &page_pair->pages[1];
|
||||
}
|
||||
BUG("No legal page\n");
|
||||
}
|
||||
|
||||
struct ckpt_page_pair *get_page_pair(struct page *page, u64 index)
|
||||
{
|
||||
struct ckpt_page_pair *page_pair;
|
||||
|
@ -118,19 +132,28 @@ int ckpt_nvm_page(struct pmobject *pmo, void *kva, u64 index)
|
|||
u64 current_version = get_current_ckpt_version();
|
||||
struct ckpt_obj_root* obj_root = container_of(pmo, struct object, opaque)->obj_root;
|
||||
if (!obj_root) {
|
||||
/* page has not been checkpointed */
|
||||
return -1;
|
||||
}
|
||||
struct page *page = virt_to_page(kva);
|
||||
struct ckpt_page_pair *page_pair = get_page_pair(page, index);
|
||||
struct ckpt_page *ckpt_page = get_latest_ckpt_page(page_pair);
|
||||
|
||||
/* nvm page use COW method, so we should update the latest ckpt page */
|
||||
// BUG_ON(ckpt_page->va != page_pair->pages[0].va);
|
||||
/* dram page use selective copy or direct-copy method,so we should update the second latest ckpt page */
|
||||
// ckpt_page = get_second_latest_ckpt_page(page_pair);
|
||||
|
||||
if (ckpt_page->version_number != current_version) {
|
||||
/* should never get the runtime page */
|
||||
BUG_ON((void*)ckpt_page->va == kva);
|
||||
|
||||
/* if the page is refered by some time traveling ckpt */
|
||||
if (ckpt_page->tt_page) {
|
||||
/**
|
||||
* (1) the time traveling ckpt will use the old page
|
||||
* (2) the two-version ckpt will use a new page
|
||||
*/
|
||||
kinfo("ckpt_nvm_page: page %lx is refered by time traveling ckpt\n", kva);
|
||||
ckpt_page->va = (vaddr_t)get_pages(0);
|
||||
ckpt_page->tt_page = NULL;
|
||||
}
|
||||
|
||||
pagecpy_nt((void*)ckpt_page->va, kva);
|
||||
ckpt_page->version_number = current_version;
|
||||
}
|
||||
|
@ -154,6 +177,7 @@ void ckpt_dram_cached_page(struct pmobject *pmo, void *kva, u64 index)
|
|||
|
||||
BUG_ON(page->pmo != pmo);
|
||||
page_pair = get_page_pair(page, index);
|
||||
page_pair->type = CKPT_PP_DRAM;
|
||||
BUG_ON(!page_pair);
|
||||
|
||||
/* dram-cached page use selective copy or direct-copy method,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
struct ckpt_page* get_latest_ckpt_page(struct ckpt_page_pair *page_pair);
|
||||
struct ckpt_page *get_second_latest_ckpt_page(struct ckpt_page_pair *page_pair);
|
||||
struct ckpt_page* get_ckpt_page_with_version(struct ckpt_page_pair *page_pair, u64 version_number);
|
||||
|
||||
struct ckpt_page_pair *get_page_pair(struct page *page, u64 index);
|
||||
void free_page_pair(struct ckpt_page_pair *page_pair);
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
#include <common/kvstore.h>
|
||||
#include <common/errno.h>
|
||||
#include <common/util.h>
|
||||
#include <object/thread.h>
|
||||
#include <ckpt/ckpt_data.h>
|
||||
#include <ckpt/ckpt.h>
|
||||
#include <arch/mmu.h>
|
||||
#include <object/cap_group.h>
|
||||
#include <mm/mm.h>
|
||||
#include <mm/kmalloc.h>
|
||||
#include <mm/nvm.h>
|
||||
#include <object/user_fault.h>
|
||||
|
||||
#include "ckpt_object_pool.h"
|
||||
#include "ckpt_objects.h"
|
||||
#include "ckpt_ws.h"
|
||||
|
||||
bool async_copying = false;
|
||||
struct time_travel_node *latest_node = NULL;
|
||||
|
||||
extern struct ckpt_ws_data *init_ckpt_ws_data();
|
||||
extern int recycle_create_ckpt(struct ckpt_recycle_data* recycle_data);
|
||||
|
||||
int init_async_copying_task(struct ckpt_obj_root *src_root_obj, u64 ckpt_name,
|
||||
u64 name_len, u64 version_number)
|
||||
{
|
||||
int r = 0;
|
||||
|
||||
if (latest_node) {
|
||||
BUG_ON(latest_node->finished == false);
|
||||
} else {
|
||||
latest_node = kzalloc(sizeof(*latest_node));
|
||||
if (!latest_node)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
async_copying = true;
|
||||
latest_node->finished = false;
|
||||
latest_node->version_number = version_number;
|
||||
latest_node->src_root_obj = src_root_obj;
|
||||
|
||||
latest_node->ckpt_data = init_ckpt_ws_data();
|
||||
if (!latest_node->ckpt_data) {
|
||||
r = -ENOMEM;
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
latest_node->obj_map = new_kvs(KVS_SIZE);
|
||||
if (!latest_node->obj_map) {
|
||||
r = -ENOMEM;
|
||||
goto out_fail_free_ckpt;
|
||||
}
|
||||
|
||||
/* init ckpt name */
|
||||
if (name_len > MAX_CKPT_NAME_LEN) {
|
||||
kinfo("[CKPT WS] only support name len < %d, truncked\n",
|
||||
MAX_CKPT_NAME_LEN);
|
||||
latest_node->ckpt_name_len = MAX_CKPT_NAME_LEN;
|
||||
} else
|
||||
latest_node->ckpt_name_len = name_len;
|
||||
|
||||
r = copy_from_user((char *)latest_node->ckpt_name,
|
||||
(char *)ckpt_name,
|
||||
latest_node->ckpt_name_len);
|
||||
if (r) {
|
||||
kinfo("[INIT ASYNC] Could not copy ckpt name from user.\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
return r;
|
||||
|
||||
out_fail_free_ckpt:
|
||||
kfree(latest_node->ckpt_data);
|
||||
out_fail:
|
||||
async_copying = false;
|
||||
latest_node->version_number = -1;
|
||||
return r;
|
||||
}
|
||||
|
||||
const obj_copy_func obj_copy_tbl[TYPE_NR] = {
|
||||
[0 ... TYPE_NR - 1] = NULL,
|
||||
[TYPE_CAP_GROUP] = ckpt_cap_group_copy,
|
||||
[TYPE_THREAD] = ckpt_thread_copy,
|
||||
[TYPE_CONNECTION] = ckpt_connection_copy,
|
||||
[TYPE_NOTIFICATION] = ckpt_notification_copy,
|
||||
[TYPE_IRQ] = ckpt_irq_copy,
|
||||
[TYPE_PMO] = ckpt_pmo_copy,
|
||||
[TYPE_VMSPACE] = ckpt_vmspace_copy,
|
||||
};
|
||||
|
||||
struct ckpt_obj_root *get_copied_obj_root(struct ckpt_obj_root *ckpt_obj_root,
|
||||
struct kvs *obj_map)
|
||||
{
|
||||
struct ckpt_obj_root *copied_obj_root = NULL;
|
||||
struct ckpt_obj_root **copied_obj_root_ptr =
|
||||
(struct ckpt_obj_root **)kvs_get(obj_map,
|
||||
(kvs_key_t *)(&ckpt_obj_root));
|
||||
struct ckpt_object *src_obj, *dst_obj;
|
||||
obj_copy_func func;
|
||||
if (copied_obj_root_ptr) {
|
||||
/* object is already copyed */
|
||||
copied_obj_root = *copied_obj_root_ptr;
|
||||
// kinfo("kvs_get: obj_map=%p key=%p, value=%p\n", obj_map,
|
||||
// ckpt_obj_root, copied_obj_root);
|
||||
} else {
|
||||
// kinfo("kvs_get: obj_map=%p key=%p FAIL\n", obj_map,
|
||||
// ckpt_obj_root);
|
||||
|
||||
/* get src_obj and dst_obj to be copied */
|
||||
src_obj = get_latest_ckpt_obj(ckpt_obj_root,
|
||||
latest_node->version_number);
|
||||
BUG_ON(!src_obj);
|
||||
|
||||
copied_obj_root = ckpt_obj_root_alloc();
|
||||
BUG_ON(!copied_obj_root);
|
||||
copied_obj_root->obj = ckpt_obj_root->obj;
|
||||
dst_obj = ckpt_obj_alloc(src_obj->type);
|
||||
if (!dst_obj) {
|
||||
goto out_fail;
|
||||
}
|
||||
copied_obj_root->ckpt_objs[0] = dst_obj; // always use first
|
||||
|
||||
/* add ckpt_obj_root <=> copied_obj_root */
|
||||
/* must put into kvs before calling function */
|
||||
// kinfo("kvs_put: obj_map=%p, key=%p, value=%p\n", obj_map,
|
||||
// ckpt_obj_root, copied_obj_root);
|
||||
kvs_put(obj_map,
|
||||
(kvs_key_t *)(&ckpt_obj_root),
|
||||
(kvs_value_t *)(&copied_obj_root));
|
||||
|
||||
/* excute copy function */
|
||||
func = obj_copy_tbl[src_obj->type];
|
||||
if (func) {
|
||||
BUG_ON(func(src_obj, dst_obj, obj_map));
|
||||
} else {
|
||||
WARN("obj copy func is NULL");
|
||||
BUG_ON(1);
|
||||
}
|
||||
}
|
||||
|
||||
copied_obj_root->time_traveling = true;
|
||||
return copied_obj_root;
|
||||
out_fail:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int sys_copy_time_traveling_data()
|
||||
{
|
||||
int r = 0;
|
||||
struct ckpt_obj_root *copied_ckpt_obj_root;
|
||||
struct ckpt_ws_data *data;
|
||||
|
||||
if (!async_copying) {
|
||||
return r;
|
||||
}
|
||||
|
||||
data = latest_node->ckpt_data;
|
||||
|
||||
/* async copy */
|
||||
BUG_ON(!latest_node || !latest_node->obj_map);
|
||||
copied_ckpt_obj_root = get_copied_obj_root(latest_node->src_root_obj,
|
||||
latest_node->obj_map);
|
||||
if (!copied_ckpt_obj_root)
|
||||
goto out_fail;
|
||||
|
||||
data->ckpt_root_obj_root = copied_ckpt_obj_root;
|
||||
|
||||
/* copy recycle data and fmap pool */
|
||||
recycle_create_ckpt(&data->recycle_data);
|
||||
fmap_fault_pool_create_ckpt(&data->ckpt_fmap_fault_pool_list);
|
||||
|
||||
/* put ckpt data into mapping and mark finished */
|
||||
r = ckpt_ws_put(latest_node->ckpt_data,
|
||||
latest_node->ckpt_name,
|
||||
latest_node->ckpt_name_len);
|
||||
if (!r) {
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
async_copying = false;
|
||||
latest_node->finished = true;
|
||||
|
||||
out_fail:
|
||||
return r;
|
||||
}
|
|
@ -156,12 +156,51 @@ struct ckpt_ws_data *ckpt_ws_get_latest()
|
|||
|
||||
latest = list_entry(CKPT_WS_TABLE->ckpt_ws_list.next,
|
||||
struct ckpt_ws_info, node);
|
||||
kinfo("[CKPT WS] latest ckpt(id=%lx) found\n", (u64)latest);
|
||||
kinfo("[CKPT WS] latest ckpt (id=%lx) found\n", (u64)latest);
|
||||
return ckpt_ws_get((u64)latest);
|
||||
}
|
||||
|
||||
/* put ckpt data */
|
||||
u64 ckpt_ws_put(struct ckpt_ws_data *ckpt_data, u64 name_buf, u64 name_len)
|
||||
u64 ckpt_ws_put(struct ckpt_ws_data *ckpt_data, char *name, u64 name_len)
|
||||
{
|
||||
struct ckpt_ws_info *info;
|
||||
int ret = 0;
|
||||
|
||||
info = (struct ckpt_ws_info *)kmalloc(sizeof(*info));
|
||||
if (!info) {
|
||||
kinfo("[CKPT WS] can not allocate memory for ckpt info.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
info->ckpt_data = ckpt_data;
|
||||
info->ts = (timestamp_t)plat_get_mono_time();
|
||||
if (name_len) {
|
||||
if (name_len > MAX_CKPT_NAME_LEN) {
|
||||
name_len = MAX_CKPT_NAME_LEN;
|
||||
}
|
||||
memcpy(info->name, name, name_len);
|
||||
}
|
||||
info->name_len = name_len;
|
||||
|
||||
/* add pair(info, data) */
|
||||
kvs_put(CKPT_WS_TABLE->ckpt_ws_kvs, (kvs_key_t *)&info,
|
||||
(kvs_value_t *)&ckpt_data);
|
||||
|
||||
/* add pair(hash(name), info*) to kvs */
|
||||
ret = __name_kvs_put(info);
|
||||
if (ret) {
|
||||
kinfo("[CKPT WS] error during add name kvs\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* add to list is atomic point */
|
||||
list_add(&(info->node), &(CKPT_WS_TABLE->ckpt_ws_list));
|
||||
|
||||
return (u64)info;
|
||||
}
|
||||
|
||||
/* put ckpt data */
|
||||
u64 ckpt_ws_put_from_userspace(struct ckpt_ws_data *ckpt_data, u64 name_buf, u64 name_len)
|
||||
{
|
||||
struct ckpt_ws_info *info;
|
||||
int ret = 0;
|
||||
|
@ -218,20 +257,31 @@ u64 ckpt_ws_put(struct ckpt_ws_data *ckpt_data, u64 name_buf, u64 name_len)
|
|||
struct ckpt_ws_info *ckpt_ws_query_by_name(char *name, u64 name_len)
|
||||
{
|
||||
ckpt_ws_info_list_t *info_list_head;
|
||||
ckpt_ws_info_list_t **info_list_head_ptr;
|
||||
u64 hash_val, ckpt_id;
|
||||
|
||||
BUG_ON(!name || name_len ==0);
|
||||
BUG_ON(!CKPT_WS_TABLE || !CKPT_WS_TABLE->name_kvs);
|
||||
|
||||
/* get info list */
|
||||
hash_val = __name_hash(name, name_len);
|
||||
info_list_head = *((ckpt_ws_info_list_t **)kvs_get(CKPT_WS_TABLE->name_kvs,
|
||||
(kvs_key_t *)&hash_val));
|
||||
|
||||
ckpt_id = __query_info_list(&(info_list_head->list), name, name_len);
|
||||
info_list_head_ptr = ((ckpt_ws_info_list_t **)kvs_get(
|
||||
CKPT_WS_TABLE->name_kvs,
|
||||
(kvs_key_t *)&hash_val));
|
||||
if (!info_list_head_ptr) {
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
info_list_head = *info_list_head_ptr;
|
||||
ckpt_id = __query_info_list(&(info_list_head->list),
|
||||
name, name_len);
|
||||
if (!ckpt_id) {
|
||||
kinfo("[CKPT WS] no ckpt found with name %s\n", name);
|
||||
return NULL;
|
||||
goto not_found;
|
||||
}
|
||||
|
||||
return (struct ckpt_ws_info *)ckpt_id;
|
||||
not_found:
|
||||
// kinfo("[CKPT WS] no ckpt found with name %s\n", name);
|
||||
return NULL;
|
||||
}
|
|
@ -8,6 +8,19 @@ typedef u64 timestamp_t;
|
|||
|
||||
#define KVS_SIZE (503)
|
||||
|
||||
struct time_travel_node {
|
||||
int version_number;
|
||||
struct ckpt_ws_data *ckpt_data;
|
||||
struct kvs *obj_map;
|
||||
struct ckpt_obj_root *src_root_obj;
|
||||
char ckpt_name[MAX_CKPT_NAME_LEN];
|
||||
u64 ckpt_name_len;
|
||||
bool finished;
|
||||
};
|
||||
|
||||
extern bool async_copying;
|
||||
extern struct time_travel_node *latest_node;
|
||||
|
||||
/*
|
||||
* store ckpt_ws_info in list, sorted by ts
|
||||
* use ckpt_id as key to map to ckpt_data
|
||||
|
@ -32,9 +45,12 @@ int ckpt_ws_init(void);
|
|||
/* get and put */
|
||||
struct ckpt_ws_data *ckpt_ws_get(u64 ckpt_id);
|
||||
struct ckpt_ws_data *ckpt_ws_get_latest();
|
||||
u64 ckpt_ws_put(struct ckpt_ws_data *ckpt_data, u64 name_buf, u64 len);
|
||||
u64 ckpt_ws_put(struct ckpt_ws_data *ckpt_data, char *name, u64 len);
|
||||
u64 ckpt_ws_put_from_userspace(struct ckpt_ws_data *ckpt_data, u64 name_buf, u64 name_len);
|
||||
|
||||
/* query utils */
|
||||
struct ckpt_ws_info *ckpt_ws_query_by_name(char *name, u64 name_len);
|
||||
ckpt_ws_info_list_t ckpt_ws_query_by_time(timestamp_t st, timestamp_t et);
|
||||
ckpt_ws_info_list_t ckpt_ws_query_latest(u64 cnt);
|
||||
|
||||
int init_async_copying_task(struct ckpt_obj_root *src_root_obj, u64 ckpt_name, u64 name_len, u64 version_number);
|
|
@ -92,8 +92,8 @@ static inline void move_runtime_nvm_page_to_backup(struct pmobject *pmo, void *k
|
|||
BUG_ON(!ckpt_obj);
|
||||
ckpt_pmo = (struct ckpt_pmobject*)ckpt_obj->opaque;
|
||||
page_pair = radix_get(ckpt_pmo->radix, index);
|
||||
if (!page_pair)
|
||||
BUG("page(%p) pmo->type=%d\n", virt_to_page(kva), pmo->type);
|
||||
BUG_ON(!page_pair);
|
||||
page_pair->type = CKPT_PP_DRAM;
|
||||
|
||||
ckpt_page = get_second_latest_ckpt_page(page_pair);
|
||||
BUG_ON(ckpt_page->va != (vaddr_t)kva);
|
||||
|
@ -119,6 +119,7 @@ move_runtime_nvm_page_from_backup(struct pmobject *pmo, u64 index)
|
|||
ckpt_pmo = (struct ckpt_pmobject*)ckpt_obj->opaque;
|
||||
page_pair = radix_get(ckpt_pmo->radix, index);
|
||||
BUG_ON(!page_pair);
|
||||
page_pair->type = CKPT_PP_NVM;
|
||||
|
||||
ckpt_page = get_latest_ckpt_page(page_pair);
|
||||
old_ckpt_page = get_second_latest_ckpt_page(page_pair);
|
||||
|
@ -219,7 +220,7 @@ static int migrate_page(struct page *old_page, bool to_dram)
|
|||
/* 2. update pte to new_pa */
|
||||
for_each_in_list(item, struct reverse_node, node, &(pmo->reverse_list)) {
|
||||
vmr = item->vmr;
|
||||
if ((vmr == NULL))
|
||||
if (vmr == NULL)
|
||||
continue;
|
||||
BUG_ON(vmr->pmo != pmo);
|
||||
#ifdef CHECK_MIGRATE
|
||||
|
|
|
@ -87,17 +87,27 @@ int sys_whole_restore(u64 ckpt_name, u64 name_len)
|
|||
goto out_fail;
|
||||
}
|
||||
set_current_ckpt_version(data->version_number);
|
||||
|
||||
/* clear the sched queues first */
|
||||
sched_clear();
|
||||
|
||||
/* restore root_cap_group obj */
|
||||
obj = restore_obj_get_by_cap_group(ckpt_obj_root, obj_map, true);
|
||||
|
||||
root_cap_group_obj_for_ckpt = obj;
|
||||
root_cap_group = (struct cap_group *)(obj->opaque);
|
||||
|
||||
/* restore other system variables */
|
||||
recycle_restore(&data->recycle_data, obj_map);
|
||||
fmap_fault_pool_restore(&data->ckpt_fmap_fault_pool_list, obj_map);
|
||||
|
||||
second_latest_ws_data = NULL;
|
||||
latest_ws_data = data;
|
||||
/* free the tmp obj map */
|
||||
kfree(obj_map);
|
||||
|
||||
if (!data->ckpt_root_obj_root->time_traveling) {
|
||||
second_latest_ws_data = NULL;
|
||||
latest_ws_data = data;
|
||||
}
|
||||
#ifdef RESTORE_REPORT
|
||||
int tcnt = 0;
|
||||
for (int i = 0; i < TYPE_NR; i++) {
|
||||
|
|
|
@ -10,13 +10,15 @@
|
|||
#define FREE_MEM_LEVEL (4)
|
||||
#define DETAIL_LEVEL (5)
|
||||
|
||||
typedef int (*obj_restore_func)(struct object *, struct ckpt_object *, struct kvs*);
|
||||
typedef int (*obj_restore_func)(struct object *, struct ckpt_object *, struct kvs*, bool time_traveling);
|
||||
typedef int (*obj_copy_func)(struct ckpt_object *, struct ckpt_object *, struct kvs*);
|
||||
|
||||
int ckpt_metadata_init(void);
|
||||
|
||||
int sys_whole_ckpt(u64 ckpt_name, u64 name_len);
|
||||
int sys_whole_ckpt_for_test(u64 ckpt_name, u64 name_len, u64 log_level);
|
||||
int sys_whole_restore(u64 ckpt_name, u64 name_len);
|
||||
int sys_copy_time_traveling_data();
|
||||
|
||||
void sys_ipi_stop_all();
|
||||
void sys_ipi_start_all();
|
||||
|
|
|
@ -103,8 +103,19 @@ struct ckpt_object_slot {
|
|||
struct ckpt_page {
|
||||
vaddr_t va;
|
||||
u64 version_number;
|
||||
/* NULL == no refered; !NULL == cow to this */
|
||||
struct ckpt_page_pair *tt_page;
|
||||
};
|
||||
|
||||
enum ckpt_page_pair_type {
|
||||
CKPT_PP_DRAM,
|
||||
CKPT_PP_NVM,
|
||||
CKPT_PP_TT,
|
||||
};
|
||||
|
||||
struct ckpt_page_pair {
|
||||
u8 type;
|
||||
u64 refcnt;
|
||||
struct ckpt_page pages[2];
|
||||
};
|
||||
|
||||
|
@ -116,6 +127,8 @@ struct ckpt_pmobject {
|
|||
pmo_type_t type;
|
||||
void *private;
|
||||
u64 flags;
|
||||
/* list of ckpt object that refers to this radix tree */
|
||||
struct list_head *cow_obj_list;
|
||||
#ifdef PMO_CHECKSUM
|
||||
u64 checksum;
|
||||
struct radix *radix_backup;
|
||||
|
@ -300,6 +313,7 @@ struct ckpt_obj_root {
|
|||
bool cow;
|
||||
int flip_flag;
|
||||
u64 refcnt;
|
||||
bool time_traveling; /* not belong to two-latest version */
|
||||
};
|
||||
|
||||
struct ckpt_ipc_server_handler_config {
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* ChCore will check each free operation in the slab allocator.
|
||||
* Please refer to kernel/mm/slab.c.
|
||||
*/
|
||||
#define DETECTING_DOUBLE_FREE_IN_SLAB OFF
|
||||
#define DETECTING_DOUBLE_FREE_IN_SLAB ON
|
||||
|
||||
/*
|
||||
* When BACKTRACE_FUNC is ON,
|
||||
|
|
|
@ -44,7 +44,7 @@ struct sleep_state {
|
|||
|
||||
extern struct list_head sleep_lists[PLAT_CPU_NUM];
|
||||
extern u64 tick_per_us;
|
||||
void sleep_state_enqueue(struct sleep_state *sleep_state); // TODO(FN): rename?
|
||||
void sleep_state_enqueue(struct sleep_state *sleep_state);
|
||||
int enqueue_sleeper(struct thread *thread, const struct timespec *timeout,
|
||||
timer_cb cb);
|
||||
bool try_dequeue_sleeper(struct thread *thread);
|
||||
|
|
|
@ -24,6 +24,7 @@ enum pageflags {
|
|||
PG_cached, /* page is moved from NVM to DRAM */
|
||||
PG_patched, /* page has patch */
|
||||
PG_flagnum,
|
||||
PG_ckpt, /* ckpt page*/
|
||||
};
|
||||
|
||||
enum page_type {
|
||||
|
|
|
@ -198,6 +198,7 @@ void switch_vmspace_to(struct vmspace *);
|
|||
void commit_page_to_pmo(struct pmobject *pmo, u64 index, paddr_t pa);
|
||||
void commit_dram_cached_page(struct pmobject *pmo, u64 index, paddr_t pa);
|
||||
void clear_dram_cached_page(struct pmobject *pmo, u64 index);
|
||||
void clear_dram_cache(struct pmobject *pmo);
|
||||
|
||||
paddr_t get_page_from_pmo(struct pmobject *pmo, u64 index);
|
||||
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
|
||||
extern struct thread *current_threads[PLAT_CPU_NUM];
|
||||
#define current_thread (current_threads[smp_get_cpu_id()])
|
||||
|
||||
extern bool resched_flags[PLAT_CPU_NUM];
|
||||
#define current_resched_flag (resched_flags[smp_get_cpu_id()])
|
||||
|
||||
#ifdef CHCORE_KERNEL_RT
|
||||
/* RT (kernel PREEMT): allocate the stack for each thread */
|
||||
#define DEFAULT_KERNEL_STACK_SZ (0x1000)
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <sched/sched.h>
|
||||
#include <common/types.h>
|
||||
|
||||
#define STATE_AREA_SIZE (sizeof(struct xsave_area))
|
||||
|
||||
void *alloc_fpu_state();
|
||||
u64 get_fpu_state_size();
|
||||
struct thread_ctx *create_thread_ctx(u32 type);
|
||||
void destroy_thread_ctx(struct thread *thread);
|
||||
void init_thread_ctx(struct thread *thread, u64 stack, u64 func, u32 prio, u32 type, s32 aff);
|
||||
|
|
|
@ -146,6 +146,8 @@ struct sched_ops {
|
|||
int (*sched_dequeue)(struct thread * thread);
|
||||
/* Debug tools */
|
||||
void (*sched_top)(void);
|
||||
/* CKPT restore tools */
|
||||
void (*sched_clear)(void);
|
||||
};
|
||||
|
||||
/* Provided Scheduling Policies */
|
||||
|
@ -172,6 +174,11 @@ static inline int sched_dequeue(struct thread *thread)
|
|||
return cur_sched_ops->sched_dequeue(thread);
|
||||
}
|
||||
|
||||
static inline void sched_clear(void)
|
||||
{
|
||||
cur_sched_ops->sched_clear();
|
||||
}
|
||||
|
||||
/* Syscalls */
|
||||
void sys_yield(void);
|
||||
void sys_top(void);
|
||||
|
|
|
@ -104,7 +104,9 @@ void handle_timer_irq(void)
|
|||
BUG_ON(wakeup_thread->sleep_state.cb == sleep_timer_cb
|
||||
&& wakeup_thread->thread_ctx->state != TS_WAITING);
|
||||
kdebug("wake up t:%p at:%ld\n", wakeup_thread, current_tick);
|
||||
BUG_ON(wakeup_thread->sleep_state.cb == NULL);
|
||||
if (wakeup_thread->sleep_state.cb == NULL) {
|
||||
BUG("wake up a thread %p: cb == NULL\n", wakeup_thread);
|
||||
}
|
||||
|
||||
wakeup_thread->sleep_state.cb(wakeup_thread);
|
||||
wakeup_thread->sleep_state.cb = NULL;
|
||||
|
@ -156,17 +158,40 @@ int sys_clock_gettime(clockid_t clock, struct timespec *ts)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void sleep_state_enqueue(struct sleep_state *sleep_state) {
|
||||
void printk_sleep_state_queue(struct sleep_state *sleep_state)
|
||||
{
|
||||
struct sleep_state *iter;
|
||||
|
||||
struct list_head *local_sleep_list = &time_states[sleep_state->sleep_cpu].sleep_list;
|
||||
kinfo("[printk_sleep_state_queue] sleep_state queue on cpu:%ld\n", sleep_state->sleep_cpu);
|
||||
for_each_in_list(iter, struct sleep_state, sleep_node,
|
||||
local_sleep_list) {
|
||||
if (iter->wakeup_tick > sleep_state->wakeup_tick)
|
||||
break;
|
||||
BUG_ON(!sleep_state->cb);
|
||||
kinfo("\t\tsleep_state:%p, wakeup_tick:%ld\n",
|
||||
iter,
|
||||
iter->wakeup_tick);
|
||||
}
|
||||
}
|
||||
|
||||
void sleep_state_enqueue(struct sleep_state *sleep_state) {
|
||||
struct sleep_state *iter, *insert;
|
||||
bool find_insert = false;
|
||||
struct list_head *local_sleep_list = &(time_states[sleep_state->sleep_cpu].sleep_list);
|
||||
insert = container_of(local_sleep_list, struct sleep_state, sleep_node);
|
||||
for_each_in_list(iter, struct sleep_state, sleep_node,
|
||||
local_sleep_list) {
|
||||
if (iter->wakeup_tick > sleep_state->wakeup_tick) {
|
||||
if (!find_insert) {
|
||||
insert = iter;
|
||||
find_insert = true;
|
||||
}
|
||||
}
|
||||
if (iter == sleep_state) {
|
||||
// kinfo("sleep state already in list\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
list_append(&sleep_state->sleep_node, &iter->sleep_node);
|
||||
list_append(&sleep_state->sleep_node, &insert->sleep_node);
|
||||
}
|
||||
|
||||
int enqueue_sleeper(struct thread *thread, const struct timespec *timeout,
|
||||
|
|
|
@ -360,11 +360,11 @@ void printk(const char *fmt, ...)
|
|||
{
|
||||
extern void lock(struct lock *lock);
|
||||
extern void unlock(struct lock *lock);
|
||||
// lock(&printk_lock);
|
||||
lock(&printk_lock);
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
simple_vsprintf(NULL, fmt, va);
|
||||
va_end(va);
|
||||
// unlock(&printk_lock);
|
||||
unlock(&printk_lock);
|
||||
}
|
||||
|
|
|
@ -94,9 +94,13 @@ void *kmalloc(size_t size)
|
|||
addr = alloc_in_slab(size);
|
||||
} else {
|
||||
if (size <= BUDDY_PAGE_SIZE)
|
||||
order = 0;
|
||||
order = 0;
|
||||
else
|
||||
order = size_to_page_order(size);
|
||||
#if TRACK_THREAD_MM == ON
|
||||
if (current_thread)
|
||||
current_thread->mm_size += (BUDDY_PAGE_SIZE * (1 << order));
|
||||
#endif
|
||||
addr = get_pages(order);
|
||||
}
|
||||
|
||||
|
|
|
@ -124,13 +124,17 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
case PMO_RING_BUFFER_RADIX:
|
||||
case PMO_ANONYM:
|
||||
case PMO_SHM: {
|
||||
|
||||
vmr_prop_t perm;
|
||||
|
||||
perm = vmr->perm;
|
||||
vmr_prop_t perm = vmr->perm;
|
||||
|
||||
/* Get the offset in the pmo for faulting addr */
|
||||
offset = ROUND_DOWN(fault_addr, PAGE_SIZE) - vmr->start;
|
||||
|
||||
/* Get the index in the pmo radix for faulting addr */
|
||||
index = offset / PAGE_SIZE;
|
||||
|
||||
/* Round down the fault address */
|
||||
fault_addr = ROUND_DOWN(fault_addr, PAGE_SIZE);
|
||||
|
||||
/* Boundary check */
|
||||
if ((offset >= pmo->size) && (pmo->type == PMO_FILE)) {
|
||||
static int warn = 1;
|
||||
|
@ -142,24 +146,17 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
warn = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* FIXME: we simply allow it now by adding new pages.
|
||||
* For PMO_FILE, users can mmap a memory that is larger
|
||||
* than the file size. If they accesses bytes beyond
|
||||
* file size, SIGBUS should be triggered on LInux.
|
||||
*
|
||||
* TODO: why setting all the perm here?
|
||||
*/
|
||||
perm = VMR_READ | VMR_WRITE | VMR_EXEC;
|
||||
} else {
|
||||
BUG_ON(offset >= pmo->size);
|
||||
}
|
||||
|
||||
/* Get the index in the pmo radix for faulting addr */
|
||||
index = offset / PAGE_SIZE;
|
||||
|
||||
fault_addr = ROUND_DOWN(fault_addr, PAGE_SIZE);
|
||||
|
||||
pa = get_page_from_pmo(pmo, index);
|
||||
|
||||
/* PMO_FILE fault means user fault */
|
||||
|
@ -182,9 +179,11 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
BUG_ON(new_va == NULL);
|
||||
pa = virt_to_phys(new_va);
|
||||
BUG_ON(pa == 0);
|
||||
|
||||
/* Clear to 0 for the newly allocated page */
|
||||
memset(new_va, 0, PAGE_SIZE);
|
||||
/*
|
||||
|
||||
/**
|
||||
* Record the physical page in the radix tree:
|
||||
* the offset is used as index in the radix tree
|
||||
*/
|
||||
|
@ -197,29 +196,35 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
perm, &pte);
|
||||
unlock(&vmspace->pgtbl_lock);
|
||||
|
||||
#ifdef EXT_SYNC_ENABLED
|
||||
/* do not persist pages belong to external sync pmo */
|
||||
if (is_external_sync_pmo(pmo))
|
||||
break;
|
||||
#endif
|
||||
#ifdef OMIT_BENCHMARK
|
||||
/* omit track page fault of redis-benchmark */
|
||||
/* omit track page fault of benchmark */
|
||||
if (need_omit(vmspace)) {
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#ifndef OMIT_PF
|
||||
page = virt_to_page(new_va);
|
||||
if ((vmspace->flags & VM_FLAG_PRESERVE) && !is_external_sync_pmo(pmo)) {
|
||||
if ((vmspace->flags & VM_FLAG_PRESERVE)
|
||||
#ifdef EXT_SYNC_ENABLED
|
||||
&& !is_external_sync_pmo(pmo)
|
||||
#endif
|
||||
) {
|
||||
#ifdef PMO_CHECKSUM
|
||||
page->ckpt_version_number = get_current_ckpt_version() + 1;
|
||||
#endif
|
||||
#ifndef OMIT_BENCHMARK
|
||||
#ifndef OMIT_BENCHMARK
|
||||
ckpt_nvm_page(pmo, new_va, index);
|
||||
#endif
|
||||
#endif
|
||||
add_pte_patch_to_pool(vmspace, (pte_t *)pte, page);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
/*
|
||||
/**
|
||||
* pa != 0: the faulting address has be committed a
|
||||
* physical page.
|
||||
*
|
||||
|
@ -240,12 +245,17 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
* needs to add the mapping in the page table.
|
||||
* Repeated mapping operations are harmless.
|
||||
*/
|
||||
|
||||
/* For PMO_FILE, we simply set all the perm now. */
|
||||
if (pmo->type == PMO_FILE) {
|
||||
perm = VMR_READ | VMR_WRITE | VMR_EXEC;
|
||||
}
|
||||
#ifndef OMIT_PF
|
||||
if ((vmspace->flags & VM_FLAG_PRESERVE) && !write && !is_external_sync_pmo(pmo)) {
|
||||
if ((vmspace->flags & VM_FLAG_PRESERVE) && !write
|
||||
#ifdef EXT_SYNC_ENABLED
|
||||
&& !is_external_sync_pmo(pmo)
|
||||
#endif
|
||||
) {
|
||||
/* Read preserved page, map as read-only */
|
||||
perm &= ~VMR_WRITE;
|
||||
}
|
||||
|
@ -320,11 +330,13 @@ int handle_trans_fault(struct vmspace *vmspace, vaddr_t fault_addr, int present,
|
|||
lock(&vmspace->pgtbl_lock);
|
||||
map_page_in_pgtbl(vmspace->pgtbl, fault_addr, pa, perm, &pte);
|
||||
unlock(&vmspace->pgtbl_lock);
|
||||
/* skip add mapping in the page table */
|
||||
skip_add_mapping:
|
||||
|
||||
#ifdef EXT_SYNC_ENABLED
|
||||
/* do not persist pages belong to external sync pmo */
|
||||
if (is_external_sync_pmo(pmo))
|
||||
break;
|
||||
#endif
|
||||
#ifndef OMIT_PF
|
||||
#ifdef OMIT_BENCHMARK
|
||||
/* omit track page fault of benchmarks */
|
||||
|
@ -334,11 +346,8 @@ skip_add_mapping:
|
|||
#endif
|
||||
if (write && (vmspace->flags & VM_FLAG_PRESERVE)) {
|
||||
page = virt_to_page((void*)phys_to_virt(pa));
|
||||
BUG_ON(unlikely(!page));
|
||||
if (unlikely(get_page_type(page) != NVM_PAGE)) {
|
||||
/* Dram page will be marked as unwritable after fork */
|
||||
break;
|
||||
}
|
||||
BUG_ON(!page);
|
||||
BUG_ON(get_page_type(page) != NVM_PAGE);
|
||||
#ifndef OMIT_MEMCPY
|
||||
/* copy page to ckpt_page */
|
||||
if (pmo != page->pmo) {
|
||||
|
@ -349,19 +358,19 @@ skip_add_mapping:
|
|||
/* Add pte patch */
|
||||
add_pte_patch_to_pool(vmspace, pte, page);
|
||||
#ifdef HYBRID_MEM
|
||||
if(!ckpt_ret)
|
||||
if (!ckpt_ret)
|
||||
track_access(page);
|
||||
#else
|
||||
UNUSED(ckpt_ret);
|
||||
#endif
|
||||
#ifdef REPORT_RUNTIME
|
||||
#ifdef REPORT_RUNTIME
|
||||
pf_count++;
|
||||
pf_tot_time += stop();
|
||||
LOG("[ckpt=%llu] [page fault count] page=%p, pte=%p\n", CKPT_VERSION_NUMBER, page, pte);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
UNUSED(ckpt_ret);
|
||||
UNUSED(ckpt_ret);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -111,6 +111,8 @@ static struct slab_header *init_slab_cache(int order, int size)
|
|||
}
|
||||
slot->next_free = NULL;
|
||||
|
||||
// printk("slab: init slab cache, order=%d, cnt=%lu\n", order, cnt);
|
||||
|
||||
return slab;
|
||||
}
|
||||
|
||||
|
|
|
@ -303,11 +303,11 @@ int pmo_clone(struct pmobject *dst_pmo, struct pmobject *src_pmo, bool *is_cow)
|
|||
case PMO_DATA_NOCACHE: {
|
||||
lock_init(&(dst_pmo->dram_cache.lock));
|
||||
|
||||
if(src_pmo->dram_cache.array != NULL) {
|
||||
if (src_pmo->dram_cache.array != NULL) {
|
||||
/* Just copy */
|
||||
*is_cow = false;
|
||||
void *new_va = kmalloc(dst_pmo->size);
|
||||
if(new_va == NULL) {
|
||||
if (new_va == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
dst_pmo->start = (paddr_t)virt_to_phys(new_va);
|
||||
|
@ -316,11 +316,11 @@ int pmo_clone(struct pmobject *dst_pmo, struct pmobject *src_pmo, bool *is_cow)
|
|||
|
||||
array = src_pmo->dram_cache.array;
|
||||
page_num = DIV_ROUND_UP(src_pmo->size, PAGE_SIZE);
|
||||
for(i = 0; i < page_num; i++) {
|
||||
for (i = 0; i < page_num; i++) {
|
||||
u64 src_pa, dst_pa = dst_pmo->start + i * PAGE_SIZE;
|
||||
if(array[i] != 0) {
|
||||
if (array[i] != 0) {
|
||||
src_pa = array[i];
|
||||
}else {
|
||||
} else {
|
||||
src_pa = src_pmo->start + i * PAGE_SIZE;
|
||||
}
|
||||
memcpy((void*)phys_to_virt(dst_pa), (void*)phys_to_virt(src_pa), PAGE_SIZE);
|
||||
|
@ -797,6 +797,14 @@ void clear_dram_cached_page(struct pmobject *pmo, u64 index)
|
|||
pmo->dram_cache.array[index] = 0;
|
||||
}
|
||||
|
||||
void clear_dram_cache(struct pmobject *pmo)
|
||||
{
|
||||
BUG_ON(!use_continuous_pages(pmo));
|
||||
BUG_ON(!pmo->dram_cache.array);
|
||||
kfree(pmo->dram_cache.array);
|
||||
pmo->dram_cache.array = NULL;
|
||||
}
|
||||
|
||||
/* Record the physical page allocated to a pmo */
|
||||
void commit_page_to_pmo(struct pmobject *pmo, u64 index, paddr_t pa)
|
||||
{
|
||||
|
@ -1160,7 +1168,11 @@ inline bool is_external_sync_pmo(struct pmobject *pmo)
|
|||
|
||||
inline bool is_shared_pmo(struct pmobject *pmo)
|
||||
{
|
||||
if (pmo->type == PMO_SHM || is_external_sync_pmo(pmo))
|
||||
if (pmo->type == PMO_SHM
|
||||
#ifdef EXT_SYNC_ENABLED
|
||||
|| is_external_sync_pmo(pmo)
|
||||
#endif
|
||||
)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -259,7 +259,8 @@ int rr_sched(void)
|
|||
/* do nothing */
|
||||
break;
|
||||
default:
|
||||
kinfo("thread state: %d\n", old->thread_ctx->state);
|
||||
// kinfo("thread state: %s\n", thread_state[old->thread_ctx->state]);
|
||||
print_thread(old);
|
||||
BUG_ON(1);
|
||||
break;
|
||||
}
|
||||
|
@ -345,10 +346,31 @@ void rr_top(void)
|
|||
}
|
||||
}
|
||||
|
||||
void rr_sched_clear()
|
||||
{
|
||||
/* clear all queues */
|
||||
int i;
|
||||
for (i = 0; i < PLAT_CPU_NUM; i++) {
|
||||
lock(&(rr_ready_queue_meta[i].queue_lock));
|
||||
rr_ready_queue_meta[i].queue_len = 0;
|
||||
init_list_head(&(rr_ready_queue_meta[i].queue_head));
|
||||
unlock(&(rr_ready_queue_meta[i].queue_lock));
|
||||
}
|
||||
|
||||
/* clear all current threads and mark resched */
|
||||
for (i = 0; i < PLAT_CPU_NUM; i++) {
|
||||
if (i == smp_get_cpu_id())
|
||||
continue;
|
||||
current_threads[i] = NULL;
|
||||
resched_flags[i] = true;
|
||||
}
|
||||
}
|
||||
|
||||
struct sched_ops rr = {
|
||||
.sched_init = rr_sched_init,
|
||||
.sched = rr_sched,
|
||||
.sched_enqueue = rr_sched_enqueue,
|
||||
.sched_dequeue = rr_sched_dequeue,
|
||||
.sched_top = rr_top
|
||||
.sched_top = rr_top,
|
||||
.sched_clear = rr_sched_clear,
|
||||
};
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
struct thread *current_threads[PLAT_CPU_NUM];
|
||||
struct thread idle_threads[PLAT_CPU_NUM];
|
||||
bool resched_flags[PLAT_CPU_NUM];
|
||||
|
||||
#if PLAT_CPU_NUM <= 32
|
||||
u32 resched_bitmaps[PLAT_CPU_NUM];
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# SLS Basic Configruations
|
||||
set(SLS_RESTORE ON)
|
||||
set(SLS_RESTORE OFF)
|
||||
set(SLS_EXT_SYNC OFF)
|
||||
set(SLS_HYBRID_MEM ON)
|
||||
|
||||
|
|
|
@ -359,6 +359,7 @@ const void *syscall_table[NR_SYSCALL] = {
|
|||
[SYS_whole_restore] = sys_whole_restore,
|
||||
[SYS_whole_ckpt_for_test] = sys_whole_ckpt_for_test,
|
||||
[SYS_register_external_ringbuf] = sys_register_external_ringbuf,
|
||||
[SYS_copy_time_traveling_data] = sys_copy_time_traveling_data,
|
||||
|
||||
/* IPI */
|
||||
[SYS_ipi_stop_all] = sys_ipi_stop_all,
|
||||
|
|
|
@ -104,6 +104,7 @@
|
|||
#define SYS_shutdown 243
|
||||
#define SYS_whole_ckpt_for_test 244
|
||||
#define SYS_register_external_ringbuf 245
|
||||
#define SYS_copy_time_traveling_data 249
|
||||
|
||||
/* IPI */
|
||||
#define SYS_ipi_stop_all 246
|
||||
|
|
|
@ -29,8 +29,8 @@ add_custom_target(
|
|||
|| echo "No custom ramdisk found, skipping"
|
||||
# archive ramdisk into ramdisk.cpio
|
||||
COMMAND find . | cpio -o -H newc > ${CMAKE_CURRENT_BINARY_DIR}/ramdisk.cpio
|
||||
DEPENDS rocksdb)
|
||||
# FIXME: ramdisk should wait for all things being copied, add more to DEPENDS.
|
||||
)
|
||||
# FIXME: ramdisk should wait for all things being copied, add more to DEPENDS.
|
||||
|
||||
include(CommonTools)
|
||||
include(UserTools)
|
||||
|
|
|
@ -190,6 +190,7 @@
|
|||
#define CHCORE_SYS_shutdown 243
|
||||
#define CHCORE_SYS_whole_ckpt_for_test 244
|
||||
#define CHCORE_SYS_register_external_ringbuf 245
|
||||
#define CHCORE_SYS_copy_time_traveling_data 249
|
||||
|
||||
/* IPI */
|
||||
#define CHCORE_SYS_ipi_stop_all 246
|
||||
|
|
|
@ -71,6 +71,7 @@ int usys_whole_ckpt(char *ckpt_name, u64 name_len);
|
|||
int usys_whole_ckpt_for_test(char *ckpt_name, u64 name_len, u64 log_level);
|
||||
int usys_whole_restore(char *ckpt_name, u64 name_len);
|
||||
int usys_register_external_ringbuf(u64 buffer);
|
||||
int usys_copy_time_traveling_data();
|
||||
|
||||
void usys_ipi_stop_all(void);
|
||||
void usys_ipi_start_all(void);
|
||||
|
|
|
@ -301,6 +301,11 @@ int usys_whole_restore(char *ckpt_name, u64 name_len)
|
|||
return chcore_syscall2(CHCORE_SYS_whole_restore, (u64)ckpt_name, name_len);
|
||||
}
|
||||
|
||||
int usys_copy_time_traveling_data()
|
||||
{
|
||||
return chcore_syscall0(CHCORE_SYS_copy_time_traveling_data);
|
||||
}
|
||||
|
||||
int usys_register_external_ringbuf(u64 buffer)
|
||||
{
|
||||
return chcore_syscall1(CHCORE_SYS_register_external_ringbuf, buffer);
|
||||
|
|
|
@ -9,6 +9,7 @@ add_executable(checkpoint.bin checkpoint.c)
|
|||
# test applications
|
||||
add_executable(test_crash_hello.bin test_crash_hello.c)
|
||||
add_executable(test_crash_counter.bin test_crash_counter.c)
|
||||
add_executable(test_time_traveling.bin test_time_traveling.c)
|
||||
|
||||
# adjust config
|
||||
add_executable(set_poll_loop_time.bin set_poll_loop_time.c)
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <chcore/type.h>
|
||||
#include <chcore/syscall.h>
|
||||
|
||||
int main(int argc, char *argv[], char *envp[])
|
||||
{
|
||||
int cnt = 0;
|
||||
usys_set_affinity(-1, 5);
|
||||
usys_yield();
|
||||
|
||||
while (1) {
|
||||
printf("[%d] hello world\n", cnt);
|
||||
usys_whole_ckpt(0, 0);
|
||||
usys_whole_ckpt("test_crash_hello", 17);
|
||||
printf("usys whole ckpt finished\n");
|
||||
usys_copy_time_traveling_data();
|
||||
printf("usys copy tt finished\n");
|
||||
usys_whole_restore("test_crash_hello", 17);
|
||||
cnt++;
|
||||
sleep(1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue