diff --git a/.gitignore b/.gitignore index a395b512..59c8f69d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ CMakeFiles CMakeCache.txt Makefile !test/*/*/Makefile +!test/signalonfork+wait/Makefile !test/*/*/*.cmd Kbuild cmake_install.cmake diff --git a/test/signalonfork+wait/Makefile b/test/signalonfork+wait/Makefile new file mode 100644 index 00000000..0350f42e --- /dev/null +++ b/test/signalonfork+wait/Makefile @@ -0,0 +1,10 @@ +# Makefile COPYRIGHT FUJITSU LIMITED 2019 +CC?=gcc +LDFLAGS=-lpthread +CFLAGS=-Wall -O0 -ggdb3 + +all: signalonfork_wait +signalonfork_wait: signalonfork_wait.o +signalonfork_wait.o: signalonfork_wait.c +clean: + rm -f signalonfork_wait.o signalonfork_wait diff --git a/test/signalonfork+wait/README b/test/signalonfork+wait/README new file mode 100644 index 00000000..c54eac9c --- /dev/null +++ b/test/signalonfork+wait/README @@ -0,0 +1,36 @@ +========== +How to run +========== + +(1) cd +(2) patch -p1 < test/signalonfork+wait/error_injection.patch +(3) Build McKernel +(4) cd /test/signalonfork+wait +(5) make +(6) edit "$HOME/.mck_test_config" + * NUMA nodes should be 0 only +(7) sh ./run.sh +(8) sh ./run_error_injection.sh + +========================== +sample of .mck_test_config +========================== + +% cat "$HOME/.mck_test_config" +# Config file for McKernel tests +: ${MCK_DIR:=/opt/usr/ihk-mckernel} +: ${BIN:=$MCK_DIR/bin} +: ${SBIN:=$MCK_DIR/sbin} +: ${OSTEST:=} +: ${LTP:=} +: ${BOOTPARAM:=-c 4-15 -m 16G} +: ${MCKERNEL_VERSION:=1.5.0} + +============ +What to test +============ + +Check for memory leaks when a fork system call and delivery of the signal occur simultaneously. + +-- +README COPYRIGHT FUJITSU LIMITED 2019 \ No newline at end of file diff --git a/test/signalonfork+wait/error_injection.patch b/test/signalonfork+wait/error_injection.patch new file mode 100644 index 00000000..219a80ca --- /dev/null +++ b/test/signalonfork+wait/error_injection.patch @@ -0,0 +1,396 @@ +error_injection.patch COPYRIGHT FUJITSU LIMITED 2019 +diff --git a/kernel/CMakeLists.txt b/kernel/CMakeLists.txt +index 608c435..b5c8518 100644 +--- a/kernel/CMakeLists.txt ++++ b/kernel/CMakeLists.txt +@@ -29,6 +29,7 @@ if (${ARCH} STREQUAL "arm64") + endif() + + set(MCKERNEL_SRCS ++ sysctrl-signalonfork_wait.c + init.c mem.c debug.c mikc.c listeners.c ap.c syscall.c cls.c host.c process.c + copy.c waitq.c futex.c timer.c plist.c fileobj.c shmobj.c zeroobj.c + procfs.c devobj.c sysfs.c xpmem.c profile.c freeze.c rbtree.c pager.c +diff --git a/kernel/include/sysctrl-signalonfork_wait.h b/kernel/include/sysctrl-signalonfork_wait.h +new file mode 100644 +index 0000000..2e4833e +--- /dev/null ++++ b/kernel/include/sysctrl-signalonfork_wait.h +@@ -0,0 +1,49 @@ ++#ifndef __SYSCTRL_SIGNALONFORK_WAIT_H__ ++#define __SYSCTRL_SIGNALONFORK_WAIT_H__ ++ ++enum signalonfork_error { ++ signalonfork_error_null = 0, ++ ++ do_fork_release_cpuid_0 = 0x010000, ++ do_fork_destroy_thread_0 = 0x010100, ++ do_fork_destroy_thread_1 = 0x010101, ++ do_fork_destroy_thread_2 = 0x010102, ++ do_fork_release_ids_0 = 0x010200, ++ do_fork_release_ids_1 = 0x010201, ++ do_fork_free_mod_clone_arg_0 = 0x010300, ++ do_fork_free_mod_clone_arg_1 = 0x010301, ++ ++ clone_thread_free_thread_0 = 0x020000, ++ clone_thread_free_thread_1 = 0x020001, ++ clone_thread_free_fp_regs_0 = 0x020100, ++ clone_thread_free_fp_regs_1 = 0x020101, ++ clone_thread_free_fork_process_proc_0 = 0x020200, ++ clone_thread_free_fork_process_proc_1 = 0x020201, ++ clone_thread_free_fork_process_asp_0 = 0x020300, ++ clone_thread_free_fork_process_vm_0 = 0x020400, ++ clone_thread_free_fork_process_cmdline_0 = 0x020500, ++ clone_thread_free_fork_process_cmdline_1 = 0x020501, ++ clone_thread_free_fork_process_mckfd_0 = 0x020600, ++ clone_thread_free_fork_clone_process_0 = 0x020700, ++ clone_thread_free_copy_user_ranges_0 = 0x020800, ++ ++ copy_user_ranges_err_rollback_0 = 0x030000, ++}; ++ ++static inline int __sof_err(enum signalonfork_error err) ++{ ++ extern enum signalonfork_error sof_error; ++ return (err == sof_error); ++} ++ ++#define sof_err(err) ({ \ ++ int ret = __sof_err(err); \ ++ if (ret) { \ ++ kprintf("sof error injection: %s\n", \ ++ #err); \ ++ } \ ++ ret; \ ++ }) ++ ++ ++#endif /*__SYSCTRL_SIGNALONFORK_WAIT_H__*/ +diff --git a/kernel/init.c b/kernel/init.c +index 9ee3b42..ecf2f79 100644 +--- a/kernel/init.c ++++ b/kernel/init.c +@@ -330,6 +330,9 @@ static void populate_sysfs(void) + numa_sysfs_setup(); + dynamic_debug_sysfs_setup(); + //setup_remote_snooping_samples(); ++ ++ extern void signalonfork_test_sysfs_setup(void); ++ signalonfork_test_sysfs_setup(); + } /* populate_sysfs() */ + + int host_ikc_inited = 0; +diff --git a/kernel/process.c b/kernel/process.c +index b2d7f34..f607198 100644 +--- a/kernel/process.c ++++ b/kernel/process.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -395,6 +396,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + IHK_MC_AP_NOWAIT)) == NULL) { + return NULL; + } ++ if (sof_err(clone_thread_free_thread_0)) { ++ goto free_thread; ++ } + + memset(thread, 0, sizeof(struct thread)); + INIT_LIST_HEAD(&thread->hash_list); +@@ -409,10 +413,17 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + ihk_mc_init_user_process(&thread->ctx, &thread->uctx, ((char *)thread) + + KERNEL_STACK_NR_PAGES * PAGE_SIZE, pc, sp); + ++ if (sof_err(clone_thread_free_thread_1)) { ++ goto free_thread; ++ } + /* copy fp_regs from parent */ + if (save_fp_regs(org)) { + goto free_thread; + } ++ if (sof_err(clone_thread_free_fp_regs_0)) { ++ goto free_fp_regs; ++ } ++ + if (copy_fp_regs(org, thread)) { + goto free_fp_regs; + } +@@ -437,23 +448,47 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + } + /* fork() */ + else { ++ if (sof_err(clone_thread_free_fp_regs_1)) { ++ goto free_fp_regs; ++ } ++ + proc = kmalloc(sizeof(struct process), IHK_MC_AP_NOWAIT); + if(!proc) + goto free_fp_regs; ++ ++ if (sof_err(clone_thread_free_fork_process_proc_0)) { ++ goto free_fork_process_proc; ++ } ++ + memset(proc, '\0', sizeof(struct process)); + init_process(proc, org->proc); + #ifdef PROFILE_ENABLE + proc->profile = org->proc->profile; + #endif + proc->termsig = termsig; ++ ++ if (sof_err(clone_thread_free_fork_process_proc_1)) { ++ goto free_fork_process_proc; ++ } ++ + asp = create_address_space(cpu_local_var(resource_set), 1); + if (!asp) { + goto free_fork_process_proc; + } ++ ++ if (sof_err(clone_thread_free_fork_process_asp_0)) { ++ goto free_fork_process_asp; ++ } ++ + proc->vm = kmalloc(sizeof(struct process_vm), IHK_MC_AP_NOWAIT); + if (!proc->vm) { + goto free_fork_process_asp; + } ++ ++ if (sof_err(clone_thread_free_fork_process_vm_0)) { ++ goto free_fork_process_vm; ++ } ++ + memset(proc->vm, '\0', sizeof(struct process_vm)); + + proc->saved_cmdline_len = org->proc->saved_cmdline_len; +@@ -462,6 +497,11 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + if (!proc->saved_cmdline) { + goto free_fork_process_vm; + } ++ ++ if (sof_err(clone_thread_free_fork_process_cmdline_0)) { ++ goto free_fork_process_cmdline; ++ } ++ + memcpy(proc->saved_cmdline, org->proc->saved_cmdline, + proc->saved_cmdline_len); + +@@ -484,6 +524,10 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + /* Copy user-space mappings. + * TODO: do this with COW later? */ + v->on_fork_vm = proc->vm; ++ if (sof_err(clone_thread_free_fork_process_cmdline_1)) { ++ v->on_fork_vm = NULL; ++ goto free_fork_process_cmdline; ++ } + if (copy_user_ranges(proc->vm, org->vm) != 0) { + v->on_fork_vm = NULL; + goto free_fork_process_cmdline; +@@ -492,6 +536,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + + /* Copy mckfd list + FIXME: Replace list manipulation with list_add() etc. */ ++ if (sof_err(clone_thread_free_copy_user_ranges_0)) { ++ goto free_fork_process_mckfd; ++ } + long irqstate = ihk_mc_spinlock_lock(&proc->mckfd_lock); + struct mckfd *cur; + for (cur = org->proc->mckfd; cur; cur = cur->next) { +@@ -517,6 +564,9 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + } + } + ihk_mc_spinlock_unlock(&proc->mckfd_lock, irqstate); ++ if (sof_err(clone_thread_free_fork_process_mckfd_0)) { ++ goto free_fork_process_mckfd; ++ } + + thread->vm->vdso_addr = org->vm->vdso_addr; + thread->vm->vvar_addr = org->vm->vvar_addr; +@@ -536,6 +586,13 @@ clone_thread(struct thread *org, unsigned long pc, unsigned long sp, + /* copy signal handlers (i.e., fork()) */ + else { + dkprintf("fork(): sigcommon\n"); ++ if (sof_err(clone_thread_free_fork_clone_process_0)) { ++ if (clone_flags & CLONE_VM) { ++ goto free_clone_process; ++ } ++ goto free_fork_process_mckfd; ++ } ++ + thread->sigcommon = kmalloc(sizeof(struct sig_common), + IHK_MC_AP_NOWAIT); + if (!thread->sigcommon) { +@@ -849,6 +906,10 @@ static int copy_user_ranges(struct process_vm *vm, struct process_vm *orgvm) + // memory_stat_rss_add() is called in child-node, i.e. copy_user_pte() + } + ++ if (sof_err(copy_user_ranges_err_rollback_0)) { ++ goto err_rollback; ++ } ++ + memory_range_write_unlock(orgvm, &irqflags); + + return 0; +diff --git a/kernel/syscall.c b/kernel/syscall.c +index 4ed043f..17bec37 100644 +--- a/kernel/syscall.c ++++ b/kernel/syscall.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -2737,6 +2738,10 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, + kprintf("do_fork,core not available\n"); + return -EAGAIN; + } ++ if (sof_err(do_fork_release_cpuid_0)) { ++ err = -EFAULT; ++ goto release_cpuid; ++ } + + new = clone_thread(old, curpc, + newsp ? newsp : cursp, clone_flags); +@@ -2747,6 +2752,10 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, + } + + newproc = new->proc; ++ if (sof_err(do_fork_destroy_thread_0)) { ++ err = -EFAULT; ++ goto destroy_thread; ++ } + + cpu_set(cpuid, &new->vm->address_space->cpu_set, + &new->vm->address_space->cpu_set_lock); +@@ -2766,8 +2775,13 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, + goto destroy_thread; + } + +- newproc->tids = kmalloc(sizeof(struct mcexec_tid) * +- NR_TIDS, IHK_MC_AP_NOWAIT); ++ if (sof_err(do_fork_destroy_thread_1)) { ++ newproc->tids = NULL; ++ } else { ++ newproc->tids = kmalloc(sizeof(struct mcexec_tid) * ++ NR_TIDS, IHK_MC_AP_NOWAIT); ++ } ++ + if (!newproc->tids) { + mcs_rwlock_writer_unlock(&newproc->threads_lock, &lock); + kfree(tids); +@@ -2775,7 +2789,12 @@ unsigned long do_fork(int clone_flags, unsigned long newsp, + goto destroy_thread; + } + +- if ((err = settid(new, NR_TIDS, tids)) < 0) { ++ if (sof_err(do_fork_release_ids_0)) { ++ err = -EFAULT; ++ } else { ++ err = settid(new, NR_TIDS, tids); ++ } ++ if (err < 0) { + mcs_rwlock_writer_unlock(&newproc->threads_lock, + &lock); + kfree(tids); +@@ -2835,7 +2854,11 @@ retry_tid: + if(oldproc->ppid_parent->pid != 1) + request1.args[0] = clone_flags; + } +- newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id()); ++ if (sof_err(do_fork_destroy_thread_2)) { ++ newproc->pid = -EFAULT; ++ } else { ++ newproc->pid = do_syscall(&request1, ihk_mc_get_processor_id()); ++ } + if (newproc->pid < 0) { + kprintf("ERROR: forking host process\n"); + err = newproc->pid; +@@ -2900,6 +2923,11 @@ retry_tid: + ihk_mc_syscall_ret(new->uctx) = 0; + + new->status = PS_RUNNING; ++ ++ if (sof_err(do_fork_release_ids_1)) { ++ err = -EFAULT; ++ goto release_ids; ++ } + + /* Only the first do_fork() call creates a thread on a Linux CPU */ + if (__sync_bool_compare_and_swap(&old->mod_clone, SPAWN_TO_REMOTE, SPAWN_TO_LOCAL)) { +@@ -2918,6 +2946,12 @@ retry_tid: + } + } + chain_thread(new); ++ ++ if (sof_err(do_fork_free_mod_clone_arg_0)) { ++ err = -EFAULT; ++ goto free_mod_clone_arg; ++ } ++ + if (!(clone_flags & CLONE_VM)) { + newproc->status = PS_RUNNING; + if(clone_flags & CLONE_PARENT){ +@@ -2960,7 +2994,12 @@ retry_tid: + request1.number = __NR_clone; + request1.args[0] = 1; + request1.args[1] = new->tid; +- err = do_syscall(&request1, ihk_mc_get_processor_id()); ++ ++ if (sof_err(do_fork_free_mod_clone_arg_1)) { ++ err = -EFAULT; ++ } else { ++ err = do_syscall(&request1, ihk_mc_get_processor_id()); ++ } + if (err) { + goto free_mod_clone_arg; + } +diff --git a/kernel/sysctrl-signalonfork_wait.c b/kernel/sysctrl-signalonfork_wait.c +new file mode 100644 +index 0000000..6995fab +--- /dev/null ++++ b/kernel/sysctrl-signalonfork_wait.c +@@ -0,0 +1,36 @@ ++#include ++#include ++#include ++#include ++ ++enum signalonfork_error sof_error; ++ ++static ssize_t signalonfork_test_show(struct sysfs_ops *ops, ++ void *instance, void *buf, size_t size) ++{ ++ return snprintf(buf, size, "%d\n", sof_error); ++} ++ ++static ssize_t signalonfork_test_store(struct sysfs_ops *ops, ++ void *instance, void *buf, size_t size) ++{ ++ sof_error = strtol(buf, NULL, 0); ++ return size; ++} ++ ++static struct sysfs_ops signalonfork_test_ops = { ++ .show = &signalonfork_test_show, ++ .store = &signalonfork_test_store, ++}; ++ ++void signalonfork_test_sysfs_setup(void) ++{ ++ int error; ++ ++ error = sysfs_createf(&signalonfork_test_ops, NULL, 0666, ++ "/sys/kernel/debug/signalonfork_test"); ++ if (error) { ++ kprintf("%s: ERROR: creating signalonfork_test sysfs file", ++ __func__); ++ } ++} diff --git a/test/signalonfork+wait/result.log b/test/signalonfork+wait/result.log new file mode 100644 index 00000000..4701c370 --- /dev/null +++ b/test/signalonfork+wait/result.log @@ -0,0 +1,78 @@ +========================= +aarch64(run.sh) +========================= +% sh run.sh +mcstop+release.sh ... done +mcreboot.sh -c 12-59 -m 2048M@4,2048M@5,2048M@6,2048M@7 -q 60 ... done +@@@ initialize: +seed for $RANDOM=13000 +@@@ run signalonfork_wait: 1..1000 +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... + +OK + +========================= +aarch64(run_error_injection.sh) +========================= +% sh run_error_injection.sh +mcstop+release.sh ... done +mcreboot.sh -c 4-51 -m 4096M ... done +@@@ initialize: +seed for $RANDOM=3466 +@@@ run signalonfork_wait(do_fork_release_cpuid_0, 0x010000) wait=1326 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_destroy_thread_0, 0x010100) wait=1201 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_destroy_thread_1, 0x010101) wait=1412 +./signalonfork_wait: pthread_create fail: Cannot allocate memory +@@@ run signalonfork_wait(do_fork_destroy_thread_2, 0x010102) wait=1041 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_release_ids_0, 0x010200) wait=1402 +./signalonfork_wait: pthread_create fail: Bad address +@@@ run signalonfork_wait(do_fork_release_ids_1, 0x010201) wait=1354 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_0, 0x010300) wait=1495 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_1, 0x010301) wait=1020 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(clone_thread_free_thread_0, 0x020000) wait=1216 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_thread_1, 0x020001) wait=1217 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fp_regs_0, 0x020100) wait=1045 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fp_regs_1, 0x020101) wait=1026 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_0, 0x020200) wait=1412 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_1, 0x020201) wait=1087 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_asp_0, 0x020300) wait=1439 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_vm_0, 0x020400) wait=1273 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_0, 0x020500) wait=1356 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_1, 0x020501) wait=1240 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_mckfd_0, 0x020600) wait=1052 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_clone_process_0, 0x020700) wait=1003 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_copy_user_ranges_0, 0x020800) wait=1465 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(copy_user_ranges_err_rollback_0, 0x030000) wait=1042 +./signalonfork_wait: fork: Cannot allocate memory +OK + +-- +result.log COPYRIGHT FUJITSU LIMITED 2019 \ No newline at end of file diff --git a/test/signalonfork+wait/result_apollo.log b/test/signalonfork+wait/result_apollo.log new file mode 100644 index 00000000..b85def90 --- /dev/null +++ b/test/signalonfork+wait/result_apollo.log @@ -0,0 +1,78 @@ +========================= +aarch64[apollo] (run.sh) +========================= +$ sh run.sh +mcstop+release.sh ... done +mcreboot.sh -c 8-55 -m 4096M -q 60 ... done +@@@ initialize: +seed for $RANDOM=8501 +@@@ run signalonfork_wait: 1..1000 +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... +.................................................................................................... + +OK + +========================= +aarch64[apollo] (run_error_injection.sh) +========================= +$ sh run_error_injection.sh +mcstop+release.sh ... done +mcreboot.sh -c 8-55 -m 4096M -q 60 ... done +@@@ initialize: +seed for $RANDOM=16838 +@@@ run signalonfork_wait(do_fork_release_cpuid_0, 0x010000) wait=1492 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_destroy_thread_0, 0x010100) wait=1368 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_destroy_thread_1, 0x010101) wait=1454 +./signalonfork_wait: pthread_create fail: Cannot allocate memory +@@@ run signalonfork_wait(do_fork_destroy_thread_2, 0x010102) wait=1014 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_release_ids_0, 0x010200) wait=1350 +./signalonfork_wait: pthread_create fail: Bad address +@@@ run signalonfork_wait(do_fork_release_ids_1, 0x010201) wait=1056 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_0, 0x010300) wait=1382 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(do_fork_free_mod_clone_arg_1, 0x010301) wait=1244 +./signalonfork_wait: fork: Bad address +@@@ run signalonfork_wait(clone_thread_free_thread_0, 0x020000) wait=1016 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_thread_1, 0x020001) wait=1455 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fp_regs_0, 0x020100) wait=1252 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fp_regs_1, 0x020101) wait=1481 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_0, 0x020200) wait=1140 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_proc_1, 0x020201) wait=1292 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_asp_0, 0x020300) wait=1355 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_vm_0, 0x020400) wait=1251 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_0, 0x020500) wait=1275 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_cmdline_1, 0x020501) wait=1451 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_process_mckfd_0, 0x020600) wait=1150 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_fork_clone_process_0, 0x020700) wait=1066 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(clone_thread_free_copy_user_ranges_0, 0x020800) wait=1484 +./signalonfork_wait: fork: Cannot allocate memory +@@@ run signalonfork_wait(copy_user_ranges_err_rollback_0, 0x030000) wait=1461 +./signalonfork_wait: fork: Cannot allocate memory +OK + +-- +result_apollo.log COPYRIGHT FUJITSU LIMITED 2019 diff --git a/test/signalonfork+wait/run.sh b/test/signalonfork+wait/run.sh new file mode 100644 index 00000000..ff983944 --- /dev/null +++ b/test/signalonfork+wait/run.sh @@ -0,0 +1,52 @@ +#!/bin/bash +# run.sh COPYRIGHT FUJITSU LIMITED 2019 +test_dir=$(dirname "${BASH_SOURCE[0]}") + +# +# read config +# +. "${test_dir}/../common.sh" + +# +# init +# +echo "@@@ initialize:" +seed="$RANDOM" +RANDOM=$seed +echo "seed for \$RANDOM=$seed" + +meminfo="/sys/devices/virtual/mcos/mcos0/sys/devices/system/node/node0/meminfo" +"${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $((1000*5)) >/dev/null +sleep 1 +exp_free_mem=`cat "$meminfo" | grep MemFree:` + +# +# run +# +nr_loop=1000 +echo "@@@ run signalonfork_wait: 1..$nr_loop" +for i in `seq 1 $nr_loop` +do + echo -n "." + new_line=$(($i % 100)) + if [ $new_line -eq 0 ]; then + echo "" + fi + + msec=$((1000 + $RANDOM % 500)) + "${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $msec >/dev/null + sleep 1 + free_mem=`cat "$meminfo" | grep MemFree:` + if [ "$exp_free_mem" != "$free_mem" ]; then + echo "" + echo "NG[$i]: detected memory leak." + echo "before:" + echo " ${exp_free_mem}" + echo "after:" + echo " ${free_mem}" + exit -1 + fi +done +echo "" +echo "OK" +exit 0 diff --git a/test/signalonfork+wait/run_error_injection.sh b/test/signalonfork+wait/run_error_injection.sh new file mode 100644 index 00000000..784d963e --- /dev/null +++ b/test/signalonfork+wait/run_error_injection.sh @@ -0,0 +1,75 @@ +#!/bin/bash +# run_error_injection.sh COPYRIGHT FUJITSU LIMITED 2019 +test_dir=$(dirname "${BASH_SOURCE[0]}") + +# +# read config +# +. "${test_dir}/../common.sh" + +# +# init +# +echo "@@@ initialize:" +seed="$RANDOM" +RANDOM=$seed +echo "seed for \$RANDOM=$seed" + +meminfo="/sys/devices/virtual/mcos/mcos0/sys/devices/system/node/node0/meminfo" +"${MCEXEC}" 0 ./signalonfork_wait -nt 1 -t $((1000*5)) >/dev/null +sleep 1 +exp_free_mem=`cat "$meminfo" | grep MemFree:` +injection="/sys/devices/virtual/mcos/mcos0/sys/kernel/debug/signalonfork_test" + +# +# run +# +while read label eq val +do + if [ -z "$label" ]; then + continue + fi + val=`echo "$val" | sed 's|,.*$||g'` + + msec=$((1000 + $RANDOM % 500)) + echo "$val" > "$injection" + echo "@@@ run signalonfork_wait($label, $val) wait=$msec" + "${MCEXEC}" 0 ./signalonfork_wait -nt 2 -t $msec > /dev/null + sleep 1 + free_mem=`cat "$meminfo" | grep MemFree:` + if [ "$exp_free_mem" != "$free_mem" ]; then + echo "NG: detected memory leak." + echo "before:" + echo " ${exp_free_mem}" + echo "after:" + echo " ${free_mem}" + exit -1 + fi +done <<__EOL__ + do_fork_release_cpuid_0 = 0x010000, + do_fork_destroy_thread_0 = 0x010100, + do_fork_destroy_thread_1 = 0x010101, + do_fork_destroy_thread_2 = 0x010102, + do_fork_release_ids_0 = 0x010200, + do_fork_release_ids_1 = 0x010201, + do_fork_free_mod_clone_arg_0 = 0x010300, + do_fork_free_mod_clone_arg_1 = 0x010301, + + clone_thread_free_thread_0 = 0x020000, + clone_thread_free_thread_1 = 0x020001, + clone_thread_free_fp_regs_0 = 0x020100, + clone_thread_free_fp_regs_1 = 0x020101, + clone_thread_free_fork_process_proc_0 = 0x020200, + clone_thread_free_fork_process_proc_1 = 0x020201, + clone_thread_free_fork_process_asp_0 = 0x020300, + clone_thread_free_fork_process_vm_0 = 0x020400, + clone_thread_free_fork_process_cmdline_0 = 0x020500, + clone_thread_free_fork_process_cmdline_1 = 0x020501, + clone_thread_free_fork_process_mckfd_0 = 0x020600, + clone_thread_free_fork_clone_process_0 = 0x020700, + clone_thread_free_copy_user_ranges_0 = 0x020800, + + copy_user_ranges_err_rollback_0 = 0x030000, +__EOL__ +echo "OK" +exit 0 diff --git a/test/signalonfork+wait/signalonfork_wait.c b/test/signalonfork+wait/signalonfork_wait.c new file mode 100644 index 00000000..6a96e9bf --- /dev/null +++ b/test/signalonfork+wait/signalonfork_wait.c @@ -0,0 +1,327 @@ +/* signalonfork_wait.c COPYRIGHT FUJITSU LIMITED 2019 */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAXNUMTHREADS 256 +#define DEFAULTTIMETOWAIT 500 + +int argc; +char **argv; +int numthreads = 1; +int nosignal; +int timetowait = DEFAULTTIMETOWAIT; + +struct timeval timeBeforeFork; +struct timeval timeBeforeTest; +struct timeval timeAfterTest; + + +#define LAPTIME_MS(start, stop) \ + ((stop.tv_sec - start.tv_sec) * 1000 + \ + (stop.tv_usec - start.tv_usec) / 1000) + +struct Thread { + int tid; + pthread_t pthread; +} thread[MAXNUMTHREADS]; + +pthread_barrier_t barrier; + +void onError(char *message) +{ + fprintf(stderr, "%s: %s: %m\n", argv[0], message); + exit(-1); +} + + +void *subjectThread(void *); + +static void waitChildren(void) +{ + for (;;) { + int status = 0; + pid_t pid = wait(&status); + + if (pid == -1) { + const char msg[] = "wait fail\n"; + + if (errno == ECHILD) { + return; + } else if (errno == EINTR) { + continue; + } + write(STDERR_FILENO, msg, sizeof(msg)); + _exit(-1); + } + } +} + +static void signal_handler(int signum, siginfo_t *info, void *uctx) +{ + waitChildren(); + if (signum == SIGTERM) { + raise(SIGTERM); + return; + } + _exit(-1); +} + +void createThreads(void) +{ + int i; + + if (pthread_barrier_init(&barrier, NULL, numthreads)) { + onError("pthread_barrier_init fail"); + } + + for (i = 1; i < numthreads; i++) { + int rval; + + thread[i].tid = i; + rval = pthread_create(&thread[i].pthread, + NULL, + subjectThread, + &thread[i]); + if (rval) { + onError("pthread_create fail"); + } + } + + thread[0].tid = 0; + thread[0].pthread = pthread_self(); + subjectThread(&thread[0]); +} + + +void joinThreads(void) +{ + int i; + + for (i = 1; i < numthreads; i++) { + void *rval; + + if (pthread_join(thread[i].pthread, &rval)) { + onError("pthread_join fail"); + } + } + + printf("Join done\n"); +} + + +void subjectTask(struct Thread *thread) +{ + pthread_barrier_wait(&barrier); + + gettimeofday(&timeBeforeTest, NULL); + printf("[%d] setup: %ld ms\n", + thread->tid, + LAPTIME_MS(timeBeforeFork, + timeBeforeTest)); + + printf("[%d] START TEST\n", thread->tid); + + for (;;) { + int pid; + + pid = fork(); + if (pid < 0) { + onError("fork"); + } else if (pid == 0) { + exit(0); + } + } + + printf("%d TEST FAIL OVERRUN\n", thread->tid); + + gettimeofday(&timeAfterTest, NULL); + + for (;;) + ; +// exit(0); +} + + +void subjectProcess(void) +{ + printf("[%d] I am a subject.\n", getpid()); + +// Subjecttask(); +} + + +void subjectCleanup(void *arg) +{ + struct Thread *thread = (struct Thread *) arg; + + printf("[%d] cleanup\n", thread->tid); +} + + +void *subjectThread(void *arg) +{ + struct Thread *thread = (struct Thread *)arg; + struct sigaction act = { + .sa_sigaction = signal_handler, + .sa_flags = SA_SIGINFO | SA_RESETHAND, + }; + + if (sigaction(SIGTERM, &act, NULL) == -1) { + onError("sigaction fail"); + } + + printf("[%d] I am a %s %d, %lx %lx\n", + getpid(), __func__, thread->tid, + thread->pthread, pthread_self()); + + pthread_cleanup_push(subjectCleanup, arg); + + //sleep(random() % 5 + 1); + //printf("[%d:%d] wake up\n", getpid(), thread->tid); + + pthread_barrier_wait(&barrier); + + subjectTask(thread); + + pthread_cleanup_pop(1); + + return NULL; +} + + +void examinerProcess(pid_t subject) +{ + struct timespec req, rem; + int status; + + printf("[%d] I am the examiner for %d.\n", getpid(), subject); + + req.tv_sec = timetowait / 1000; + req.tv_nsec = (timetowait % 1000) * 1000000; + + if (nanosleep(&req, &rem) < 0) { + fprintf(stderr, "nanosleep is interrupted, but ignore\n"); + } + + if (kill(subject, SIGTERM) < 0) { + printf("TEST FAIL (EXIT ALREADY)\n"); + exit(-1); + } + + if (waitpid(subject, &status, 0) < 0) { + onError("waitpid fail"); + } + + if (WIFEXITED(status)) { + printf("The TEST process unexpectedly " + "exited with return value %d\n", + WEXITSTATUS(status)); + printf("TEST FAILED\n"); + if (WEXITSTATUS(status) == 0) { + exit(-1); + } else { + exit(WEXITSTATUS(status)); + } + return; + } + + if (WIFSIGNALED(status)) { + printf("The TEST process is terminated by the signal %d\n", + WTERMSIG(status)); + if (WTERMSIG(status) == SIGTERM) { + printf("TEST SUCCEEDED\n"); + } else { + printf("TEST FAILED\n"); + exit(WTERMSIG(status)); + } + } + +// printf("TEST SUCCEEDED IF YOU DID NOT SEE 'OVERRUN'\n"); +// printf("TEST FINISHED\n"); +} + + +int main(int _argc, char **_argv) +{ + pid_t pid; + int i; + + argc = _argc; + argv = _argv; + + printf("DANGERTEST SIGNALONFORK\n"); + + for (i = 1; i < argc; i++) { + if (strcmp("-nt", argv[i]) == 0) { + i++; + if (i < argc) { + numthreads = atoi(argv[i]); + continue; + } + fprintf(stderr, "%s: num threads required\n", argv[0]); + exit(-1); + } + if (strcmp("-nosignal", argv[i]) == 0) { + nosignal = 1; + continue; + } + if (strcmp("-t", argv[i]) == 0) { + i++; + if (i < argc) { + timetowait = atoi(argv[i]); + continue; + } + } + fprintf(stderr, "%s: argument error\n" + "Usage:\n" + "\t-nt \n" + "\t-nosignal\n" + "\t-t