This is a delta against Oren's v17-rc1. The code is pretty much the same as it was in v15; I mostly cherry-picked the original commits and fixed the build breaks. Single-task checkpoint and restart of 32-bit bash works... sometimes. I think I may be seeing the same issue I reported for i386 here: https://lists.linux-foundation.org/pipermail/containers/2009-June/018522.html Note clone_with_pids is not implemented yet. Tested with 64-bit kernel on Powerstation (970MP). Comments welcome... arch/powerpc/Kconfig | 3 + arch/powerpc/include/asm/Kbuild | 1 + arch/powerpc/include/asm/checkpoint_hdr.h | 13 + arch/powerpc/include/asm/ptrace.h | 7 + arch/powerpc/include/asm/systbl.h | 2 + arch/powerpc/include/asm/unistd.h | 4 +- arch/powerpc/kernel/ptrace.c | 88 ++++-- arch/powerpc/mm/Makefile | 1 + arch/powerpc/mm/checkpoint.c | 499 +++++++++++++++++++++++++++++ checkpoint/process.c | 50 --- include/linux/Kbuild | 1 + include/linux/checkpoint_hdr.h | 2 + 12 files changed, 591 insertions(+), 80 deletions(-) diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index d00131c..2ca160e 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig @@ -26,6 +26,9 @@ config MMU bool default y +config CHECKPOINT_SUPPORT + def_bool y + config GENERIC_CMOS_UPDATE def_bool y diff --git a/arch/powerpc/include/asm/Kbuild b/arch/powerpc/include/asm/Kbuild index 5ab7d7f..20379f1 100644 --- a/arch/powerpc/include/asm/Kbuild +++ b/arch/powerpc/include/asm/Kbuild @@ -12,6 +12,7 @@ header-y += shmbuf.h header-y += socket.h header-y += termbits.h header-y += fcntl.h +header-y += checkpoint_hdr.h header-y += poll.h header-y += sockios.h header-y += ucontext.h diff --git a/arch/powerpc/include/asm/checkpoint_hdr.h b/arch/powerpc/include/asm/checkpoint_hdr.h new file mode 100644 index 0000000..2d454c6 --- /dev/null +++ b/arch/powerpc/include/asm/checkpoint_hdr.h @@ -0,0 +1,13 @@ +#ifndef __ASM_POWERPC_CKPT_HDR_H +#define __ASM_POWERPC_CKPT_HDR_H + +/* This must match _NSIG in <asm/signal.h> */ +#define CKPT_ARCH_NSIG 64 + +#ifdef __powerpc64__ +#define CKPT_ARCH_ID CKPT_ARCH_PPC64 +#else +#define CKPT_ARCH_ID CKPT_ARCH_PPC32 +#endif + +#endif /* __ASM_POWERPC_CKPT_HDR_H */ diff --git a/arch/powerpc/include/asm/ptrace.h b/arch/powerpc/include/asm/ptrace.h index 8c34149..c6cb2c6 100644 --- a/arch/powerpc/include/asm/ptrace.h +++ b/arch/powerpc/include/asm/ptrace.h @@ -81,6 +81,8 @@ struct pt_regs { #ifndef __ASSEMBLY__ +#include <linux/types.h> + #define instruction_pointer(regs) ((regs)->nip) #define user_stack_pointer(regs) ((regs)->gpr[1]) #define regs_return_value(regs) ((regs)->gpr[3]) @@ -140,6 +142,11 @@ extern void user_enable_single_step(struct task_struct *); extern void user_enable_block_step(struct task_struct *); extern void user_disable_single_step(struct task_struct *); +/* for reprogramming DABR/DAC during restart of a checkpointed task */ +extern bool debugreg_valid(unsigned long val, unsigned int index); +extern void debugreg_update(struct task_struct *task, unsigned long val, + unsigned int index); + #endif /* __ASSEMBLY__ */ #endif /* __KERNEL__ */ diff --git a/arch/powerpc/include/asm/systbl.h b/arch/powerpc/include/asm/systbl.h index 370600c..3d44cf3 100644 --- a/arch/powerpc/include/asm/systbl.h +++ b/arch/powerpc/include/asm/systbl.h @@ -326,3 +326,5 @@ SYSCALL_SPU(perf_counter_open) COMPAT_SYS_SPU(preadv) COMPAT_SYS_SPU(pwritev) COMPAT_SYS(rt_tgsigqueueinfo) +SYSCALL(checkpoint) +SYSCALL(restart) diff --git a/arch/powerpc/include/asm/unistd.h b/arch/powerpc/include/asm/unistd.h index cef080b..ef41ebb 100644 --- a/arch/powerpc/include/asm/unistd.h +++ b/arch/powerpc/include/asm/unistd.h @@ -345,10 +345,12 @@ #define __NR_preadv 320 #define __NR_pwritev 321 #define __NR_rt_tgsigqueueinfo 322 +#define __NR_checkpoint 323 +#define __NR_restart 324 #ifdef __KERNEL__ -#define __NR_syscalls 323 +#define __NR_syscalls 325 #define __NR__exit __NR_exit #define NR_syscalls __NR_syscalls diff --git a/arch/powerpc/kernel/ptrace.c b/arch/powerpc/kernel/ptrace.c index 9fa2c7d..15ab4be 100644 --- a/arch/powerpc/kernel/ptrace.c +++ b/arch/powerpc/kernel/ptrace.c @@ -754,22 +754,25 @@ void user_disable_single_step(struct task_struct *task) clear_tsk_thread_flag(task, TIF_SINGLESTEP); } -int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, - unsigned long data) +/** + * debugreg_valid() - validate the value to be written to a debug register + * @val: The prospective contents of the register. + * @index: Must be zero. + * + * Returns true if @val is an acceptable value for the register indicated by + * @index, false otherwise. + */ +bool debugreg_valid(unsigned long val, unsigned int index) { - /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). - * For embedded processors we support one DAC and no IAC's at the - * moment. - */ - if (addr > 0) - return -EINVAL; + /* We support only one debug register for now */ + if (index != 0) + return false; /* The bottom 3 bits in dabr are flags */ - if ((data & ~0x7UL) >= TASK_SIZE) - return -EIO; + if ((val & ~0x7UL) >= TASK_SIZE) + return false; #ifndef CONFIG_BOOKE - /* For processors using DABR (i.e. 970), the bottom 3 bits are flags. * It was assumed, on previous implementations, that 3 bits were * passed together with the data address, fitting the design of the @@ -783,47 +786,74 @@ int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, */ /* Ensure breakpoint translation bit is set */ - if (data && !(data & DABR_TRANSLATION)) - return -EIO; - - /* Move contents to the DABR register */ - task->thread.dabr = data; - -#endif -#if defined(CONFIG_BOOKE) - + if (val && !(val & DABR_TRANSLATION)) + return false; +#else /* As described above, it was assumed 3 bits were passed with the data * address, but we will assume only the mode bits will be passed * as to not cause alignment restrictions for DAC-based processors. */ + /* Read or Write bits must be set */ + if (!(val & 0x3UL)) + return -EINVAL; +#endif + return true; +} + +/** + * debugreg_update() - update a debug register associated with a task + * @task: The task whose register state is to be modified. + * @val: The value to be written to the debug register. + * @index: Specifies the debug register. Currently unused. + * + * Set a task's DABR/DAC to @val, which should be validated with + * debugreg_valid() beforehand. + */ +void debugreg_update(struct task_struct *task, unsigned long val, + unsigned int index) +{ +#ifndef CONFIG_BOOKE + task->thread.dabr = val; +#else /* DAC's hold the whole address without any mode flags */ - task->thread.dabr = data & ~0x3UL; + task->thread.dabr = val & ~0x3UL; if (task->thread.dabr == 0) { task->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | DBCR0_IDM); task->thread.regs->msr &= ~MSR_DE; - return 0; } - /* Read or Write bits must be set */ - - if (!(data & 0x3UL)) - return -EINVAL; - /* Set the Internal Debugging flag (IDM bit 1) for the DBCR0 register */ task->thread.dbcr0 = DBCR0_IDM; /* Check for write and read flags and set DBCR0 accordingly */ - if (data & 0x1UL) + if (val & 0x1UL) task->thread.dbcr0 |= DBSR_DAC1R; - if (data & 0x2UL) + if (val & 0x2UL) task->thread.dbcr0 |= DBSR_DAC1W; task->thread.regs->msr |= MSR_DE; #endif +} + +static int ptrace_set_debugreg(struct task_struct *task, unsigned long addr, + unsigned long data) +{ + /* For ppc64 we support one DABR and no IABR's at the moment (ppc64). + * For embedded processors we support one DAC and no IAC's at the + * moment. + */ + if (addr > 0) + return -EINVAL; + + if (!debugreg_valid(data, 0)) + return -EIO; + + debugreg_update(task, data, 0); + return 0; } diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 3e68363..aa8733c 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile @@ -31,3 +31,4 @@ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o obj-$(CONFIG_HIGHMEM) += highmem.o +obj-$(CONFIG_CHECKPOINT) += checkpoint.o diff --git a/arch/powerpc/mm/checkpoint.c b/arch/powerpc/mm/checkpoint.c new file mode 100644 index 0000000..9f7de42 --- /dev/null +++ b/arch/powerpc/mm/checkpoint.c @@ -0,0 +1,499 @@ +/* + * Checkpoint/restart - architecture specific support for powerpc. + * Based on x86 implementation. + * + * Copyright (C) 2008 Oren Laadan + * Copyright 2009 IBM Corp. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of the Linux + * distribution for more details. + */ + +#define DEBUG 1 /* for pr_debug */ + +#include <linux/checkpoint.h> +#include <linux/checkpoint_hdr.h> +#include <linux/kernel.h> +#include <asm/processor.h> +#include <asm/ptrace.h> +#include <asm/system.h> + +enum ckpt_cpu_feature { + CKPT_USED_FP, + CKPT_USED_DEBUG, + CKPT_USED_ALTIVEC, + CKPT_USED_SPE, + CKPT_USED_VSX, + CKPT_FTR_END = 31, +}; + +#define x(ftr) (1UL << ftr) + +/* features this kernel can handle for restart */ +enum { + CKPT_FTRS_POSSIBLE = +#ifdef CONFIG_PPC_FPU + x(CKPT_USED_FP) | +#endif + x(CKPT_USED_DEBUG) | +#ifdef CONFIG_ALTIVEC + x(CKPT_USED_ALTIVEC) | +#endif +#ifdef CONFIG_SPE + x(CKPT_USED_SPE) | +#endif +#ifdef CONFIG_VSX + x(CKPT_USED_VSX) | +#endif + 0, +}; + +#undef x + +struct ckpt_hdr_cpu { + struct ckpt_hdr h; + u32 features_used; + u32 pt_regs_size; + u32 fpr_size; + struct pt_regs pt_regs; + /* relevant fields from thread_struct */ + double fpr[32][TS_FPRWIDTH]; + u32 fpscr; + s32 fpexc_mode; + u64 dabr; + /* Altivec/VMX state */ + vector128 vr[32]; + vector128 vscr; + u64 vrsave; + /* SPE state */ + u32 evr[32]; + u64 acc; + u32 spefscr; +}; + +/************************************************************************** + * Checkpoint + */ + +static void ckpt_cpu_feature_set(struct ckpt_hdr_cpu *hdr, + enum ckpt_cpu_feature ftr) +{ + hdr->features_used |= 1ULL << ftr; +} + +static bool ckpt_cpu_feature_isset(const struct ckpt_hdr_cpu *hdr, + enum ckpt_cpu_feature ftr) +{ + return hdr->features_used & (1ULL << ftr); +} + +/* determine whether an image has feature bits set that this kernel + * does not support */ +static bool ckpt_cpu_features_unknown(const struct ckpt_hdr_cpu *hdr) +{ + return hdr->features_used & ~CKPT_FTRS_POSSIBLE; +} + +static void checkpoint_gprs(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + struct pt_regs *pt_regs; + + pr_debug("%s: saving GPRs\n", __func__); + + cpu_hdr->pt_regs_size = sizeof(*pt_regs); + pt_regs = task_pt_regs(task); + cpu_hdr->pt_regs = *pt_regs; +} + +#ifdef CONFIG_PPC_FPU +static void checkpoint_fpu(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + /* easiest to save FP state unconditionally */ + + pr_debug("%s: saving FPU state\n", __func__); + + if (task == current) + flush_fp_to_thread(task); + + cpu_hdr->fpr_size = sizeof(cpu_hdr->fpr); + cpu_hdr->fpscr = task->thread.fpscr.val; + cpu_hdr->fpexc_mode = task->thread.fpexc_mode; + + memcpy(cpu_hdr->fpr, task->thread.fpr, sizeof(cpu_hdr->fpr)); + + ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_FP); +} +#else +static void checkpoint_fpu(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + return; +} +#endif + +#ifdef CONFIG_ALTIVEC +static void checkpoint_altivec(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + return; + + if (!task->thread.used_vr) + return; + + pr_debug("%s: saving Altivec state\n", __func__); + + if (task == current) + flush_altivec_to_thread(task); + + cpu_hdr->vrsave = task->thread.vrsave; + memcpy(cpu_hdr->vr, task->thread.vr, sizeof(cpu_hdr->vr)); + ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_ALTIVEC); +} +#else +static void checkpoint_altivec(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + return; +} +#endif + +#ifdef CONFIG_SPE +static void checkpoint_spe(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + if (!cpu_has_feature(CPU_FTR_SPE)) + return; + + if (!task->thread.used_spe) + return; + + pr_debug("%s: saving SPE state\n", __func__); + + if (task == current) + flush_spe_to_thread(task); + + cpu_hdr->acc = task->thread.acc; + cpu_hdr->spefscr = task->thread.spefscr; + memcpy(cpu_hdr->evr, task->thread.evr, sizeof(cpu_hdr->evr)); + ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_SPE); +} +#else +static void checkpoint_spe(struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task) +{ + return; +} +#endif + +static void checkpoint_dabr(struct ckpt_hdr_cpu *cpu_hdr, + const struct task_struct *task) +{ + if (!task->thread.dabr) + return; + + cpu_hdr->dabr = task->thread.dabr; + ckpt_cpu_feature_set(cpu_hdr, CKPT_USED_DEBUG); +} + +/* dump the thread_struct of a given task */ +int checkpoint_thread(struct ckpt_ctx *ctx, struct task_struct *t) +{ + return 0; +} + +/* dump the cpu state and registers of a given task */ +int checkpoint_cpu(struct ckpt_ctx *ctx, struct task_struct *t) +{ + struct ckpt_hdr_cpu *cpu_hdr; + int rc; + + rc = -ENOMEM; + cpu_hdr = ckpt_hdr_get_type(ctx, sizeof(*cpu_hdr), CKPT_HDR_CPU); + if (!cpu_hdr) + goto err; + + checkpoint_gprs(cpu_hdr, t); + checkpoint_fpu(cpu_hdr, t); + checkpoint_dabr(cpu_hdr, t); + checkpoint_altivec(cpu_hdr, t); + checkpoint_spe(cpu_hdr, t); + + rc = ckpt_write_obj(ctx, (struct ckpt_hdr *) cpu_hdr); +err: + ckpt_hdr_put(ctx, cpu_hdr); + return rc; +} + +int checkpoint_write_header_arch(struct ckpt_ctx *ctx) +{ + return 0; +} + +/* dump the mm->context state */ +int checkpoint_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm) +{ + return 0; +} + +/************************************************************************** + * Restart + */ + +/* read the thread_struct into the current task */ +int restore_thread(struct ckpt_ctx *ctx) +{ + return 0; +} + +/* Based on the MSR value from a checkpoint image, produce an MSR + * value that is appropriate for the restored task. Right now we only + * check for MSR_SF (64-bit) for PPC64. + */ +static unsigned long sanitize_msr(unsigned long msr_ckpt) +{ +#ifdef CONFIG_PPC32 + return MSR_USER; +#else + if (msr_ckpt & MSR_SF) + return MSR_USER64; + return MSR_USER32; +#endif +} + +static int restore_gprs(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + struct pt_regs *regs; + int rc; + + rc = -EINVAL; + if (cpu_hdr->pt_regs_size != sizeof(*regs)) + goto out; + + rc = 0; + if (!update) + goto out; + + regs = task_pt_regs(task); + *regs = cpu_hdr->pt_regs; + + regs->msr = sanitize_msr(regs->msr); +out: + return rc; +} + +#ifdef CONFIG_PPC_FPU +static int restore_fpu(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + int rc; + + rc = -EINVAL; + if (cpu_hdr->fpr_size != sizeof(task->thread.fpr)) + goto out; + + rc = 0; + if (!update || !ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_FP)) + goto out; + + task->thread.fpscr.val = cpu_hdr->fpscr; + task->thread.fpexc_mode = cpu_hdr->fpexc_mode; + + memcpy(task->thread.fpr, cpu_hdr->fpr, sizeof(task->thread.fpr)); +out: + return rc; +} +#else +static int restore_fpu(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + WARN_ON_ONCE(ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_FP)); + return 0; +} +#endif + +static int restore_dabr(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + int rc; + + rc = 0; + if (!ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_DEBUG)) + goto out; + + rc = -EINVAL; + if (!debugreg_valid(cpu_hdr->dabr, 0)) + goto out; + + rc = 0; + if (!update) + goto out; + + debugreg_update(task, cpu_hdr->dabr, 0); +out: + return rc; +} + +#ifdef CONFIG_ALTIVEC +static int restore_altivec(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + int rc; + + rc = 0; + if (!ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_ALTIVEC)) + goto out; + + rc = -EINVAL; + if (!cpu_has_feature(CPU_FTR_ALTIVEC)) + goto out; + + rc = 0; + if (!update) + goto out; + + task->thread.vrsave = cpu_hdr->vrsave; + task->thread.used_vr = 1; + + memcpy(task->thread.vr, cpu_hdr->vr, sizeof(cpu_hdr->vr)); +out: + return rc; +} +#else +static int restore_altivec(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + WARN_ON_ONCE(ckpt_cpu_feature_isset(CKPT_USED_ALTIVEC)); + return 0; +} +#endif + +#ifdef CONFIG_SPE +static int restore_spe(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + int rc; + + rc = 0; + if (!ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_SPE)) + goto out; + + rc = -EINVAL; + if (!cpu_has_feature(CPU_FTR_SPE)) + goto out; + + rc = 0; + if (!update) + goto out; + + task->thread.acc = cpu_hdr->acc; + task->thread.spefscr = cpu_hdr->spefscr; + task->thread.used_spe = 1; + + memcpy(task->thread.evr, cpu_hdr->evr, sizeof(cpu_hdr->evr)); +out: + return rc; +} +#else +static int restore_spe(const struct ckpt_hdr_cpu *cpu_hdr, + struct task_struct *task, bool update) +{ + WARN_ON_ONCE(ckpt_cpu_feature_isset(cpu_hdr, CKPT_USED_SPE)); + return 0; +} +#endif + +struct restore_func_desc { + int (*func)(const struct ckpt_hdr_cpu *, struct task_struct *, bool); + const char *info; +}; + +typedef int (*restore_func_t)(const struct ckpt_hdr_cpu *, + struct task_struct *, bool); + +static const restore_func_t restore_funcs[] = { + restore_gprs, + restore_fpu, + restore_dabr, + restore_altivec, + restore_spe, +}; + +static bool bitness_match(const struct ckpt_hdr_cpu *cpu_hdr, + const struct task_struct *task) +{ + /* 64-bit image */ + if (cpu_hdr->pt_regs.msr & MSR_SF) { + if (task->thread.regs->msr & MSR_SF) + return true; + else + return false; + } + + /* 32-bit image */ + if (task->thread.regs->msr & MSR_SF) + return false; + + return true; +} + +int restore_cpu(struct ckpt_ctx *ctx) +{ + struct ckpt_hdr_cpu *cpu_hdr; + bool update; + int rc; + int i; + + cpu_hdr = ckpt_read_obj_type(ctx, sizeof(*cpu_hdr), CKPT_HDR_CPU); + if (IS_ERR(cpu_hdr)) + return PTR_ERR(cpu_hdr); + + rc = -EINVAL; + if (ckpt_cpu_features_unknown(cpu_hdr)) + goto err; + + /* temporary: restoring a 32-bit image from a 64-bit task and + * vice-versa is known not to work (probably not restoring + * thread_info correctly); detect this and fail gracefully. + */ + if (!bitness_match(cpu_hdr, current)) + goto err; + + /* We want to determine whether there's anything wrong with + * the checkpoint image before changing the task at all. Run + * a "check" phase (update = false) first. + */ + update = false; +commit: + for (i = 0; i < ARRAY_SIZE(restore_funcs); i++) { + rc = restore_funcs[i](cpu_hdr, current, update); + if (rc == 0) + continue; + pr_debug("%s: restore_func[%i] failed\n", __func__, i); + WARN_ON_ONCE(update); + goto err; + } + + if (!update) { + update = true; + goto commit; + } + +err: + ckpt_hdr_put(ctx, cpu_hdr); + return rc; +} + +int restore_read_header_arch(struct ckpt_ctx *ctx) +{ + return 0; +} + +int restore_mm_context(struct ckpt_ctx *ctx, struct mm_struct *mm) +{ + return 0; +} diff --git a/checkpoint/process.c b/checkpoint/process.c index a93df3d..cfdce42 100644 --- a/checkpoint/process.c +++ b/checkpoint/process.c @@ -229,28 +229,6 @@ int checkpoint_restart_block(struct ckpt_ctx *ctx, struct task_struct *t) ckpt_debug("restart_block: posix_cpu expire %lld now %lld\n", expire, base); -#ifdef CONFIG_COMPAT - } else if (fn == compat_nanosleep_restart) { - - h->function_type = CKPT_RESTART_BLOCK_NANOSLEEP; - h->arg_0 = restart_block->nanosleep.index; - h->arg_1 = (unsigned long)restart_block->nanosleep.rmtp; - h->arg_2 = (unsigned long)restart_block->nanosleep.compat_rmtp; - expire = restart_block->nanosleep.expires; - ckpt_debug("restart_block: compat expire %lld now %lld\n", - expire, base); - - } else if (fn == compat_clock_nanosleep_restart) { - - h->function_type = CKPT_RESTART_BLOCK_COMPAT_CLOCK_NANOSLEEP; - h->arg_0 = restart_block->nanosleep.index; - h->arg_1 = (unsigned long)restart_block->nanosleep.rmtp; - h->arg_2 = (unsigned long)restart_block->nanosleep.compat_rmtp; - expire = restart_block->nanosleep.expires; - ckpt_debug("restart_block: compat_clock expire %lld now %lld\n", - expire, base); - -#endif } else if (fn == futex_wait_restart) { h->function_type = CKPT_RESTART_BLOCK_FUTEX; @@ -567,34 +545,6 @@ int restore_restart_block(struct ckpt_ctx *ctx) restart_block.arg2 = ts.tv_sec; restart_block.arg3 = ts.tv_nsec; break; -#ifdef CONFIG_COMPAT - case CKPT_RESTART_BLOCK_COMPAT_NANOSLEEP: - clockid = h->arg_0; - if (clockid < 0 || invalid_clockid(clockid)) - break; - restart_block.fn = compat_nanosleep_restart; - restart_block.nanosleep.index = clockid; - restart_block.nanosleep.rmtp = - (struct timespec __user *) (unsigned long) h->arg_1; - restart_block.nanosleep.compat_rmtp = - (struct compat_timespec __user *) - (unsigned long) h->arg_2; - resatrt_block.nanosleep.expires = expire; - break; - case CKPT_RESTART_BLOCK_COMPAT_CLOCK_NANOSLEEP: - clockid = h->arg_0; - if (clockid < 0 || invalid_clockid(clockid)) - break; - restart_block.fn = compat_clock_nanosleep_restart; - restart_block.nanosleep.index = clockid; - restart_block.nanosleep.rmtp = - (struct timespec __user *) (unsigned long) h->arg_1; - restart_block.nanosleep.compat_rmtp = - (struct compat_timespec __user *) - (unsigned long) h->arg_2; - resatrt_block.nanosleep.expires = expire; - break; -#endif case CKPT_RESTART_BLOCK_FUTEX: restart_block.fn = futex_wait_restart; restart_block.futex.uaddr = (u32 *) (unsigned long) h->arg_0; diff --git a/include/linux/Kbuild b/include/linux/Kbuild index 861c7fa..b6677b9 100644 --- a/include/linux/Kbuild +++ b/include/linux/Kbuild @@ -46,6 +46,7 @@ header-y += can.h header-y += cdk.h header-y += checkpoint_types.h header-y += checkpoint_hdr.h +header-y += checkpoint.h header-y += chio.h header-y += coda_psdev.h header-y += coff.h diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h index b5243e1..d999b5c 100644 --- a/include/linux/checkpoint_hdr.h +++ b/include/linux/checkpoint_hdr.h @@ -98,6 +98,8 @@ enum { /* do not change order (will break ABI) */ CKPT_ARCH_X86_32 = 1, CKPT_ARCH_S390X, + CKPT_ARCH_PPC32, + CKPT_ARCH_PPC64, }; /* shared objrects (objref) */ _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers