aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaoya Horiguchi <[n-horiguchi@ah.jp.nec.com]>2009-10-28 11:20:47 +0100
committerAndi Kleen <ak@linux.intel.com>2009-10-28 11:20:59 +0100
commitc75a980bc51142e0ad79728aa63410c8eaa205c0 (patch)
tree100a21cb373c7702c5ee00e0c3c3a5eb1fe07956
parentec5452c583211f93a80c197731ea45efdf64ad5f (diff)
downloadmce-test-c75a980bc51142e0ad79728aa63410c8eaa205c0.tar.gz
tinjpage: add test case for mmap/ipv shared pages
This patch adds the testcases for mmap/IPV shared pages. The purpose of these testcases is as follows: - We can check whether a process A is killed expectedly when it accesses the page shared with and hwpoisoned by another process B (in the late killing case). - We can check whether a process A is killed at once when another process B injected hwpoison into the page shared by both of them (in the early killing case). ChangeLog: - Add synchronization code between parent and child process with semaphore. - Share the common function do_shared() between mmap case and IPV case. - Add error chack code. Signed-off-by: Naoya Horiguchi <n-horiguchi@ah.jp.nec.com> Signed-off-by: Andi Kleen <ak@linux.intel.com>
-rw-r--r--tsrc/tinjpage.c160
1 files changed, 160 insertions, 0 deletions
diff --git a/tsrc/tinjpage.c b/tsrc/tinjpage.c
index 8b206c7..3db2ea8 100644
--- a/tsrc/tinjpage.c
+++ b/tsrc/tinjpage.c
@@ -32,6 +32,9 @@
#include <string.h>
#include <time.h>
#include <pthread.h>
+#include <sys/ipc.h>
+#include <sys/shm.h>
+#include <sys/sem.h>
#define MADV_POISON 100
@@ -497,6 +500,161 @@ static void under_io_clean(void)
close(fd);
}
+/*
+ * semaphore get/put wrapper
+ */
+int get_semaphore(int sem_id, struct sembuf *sembuffer)
+{
+ sembuffer->sem_num = 0;
+ sembuffer->sem_op = -1;
+ sembuffer->sem_flg = SEM_UNDO;
+ return semop(sem_id, sembuffer, 1);
+}
+
+int put_semaphore(int sem_id, struct sembuf *sembuffer)
+{
+ sembuffer->sem_num = 0;
+ sembuffer->sem_op = 1;
+ sembuffer->sem_flg = SEM_UNDO;
+ return semop(sem_id, sembuffer, 1);
+}
+
+/* memory sharing mode */
+enum shared_mode {
+ MMAP_SHARED = 0,
+ IPV_SHARED = 1,
+};
+
+/*
+ * testcase for shared pages, where
+ * if early_kill == 0, parent access the shared page hwpoisoned by child, and
+ * if early_kill == 1, parent will be killed by SIGBUS from child.
+ * This testcase checks whether if a shared page is hwpoisoned by one process,
+ * another process sharing the page will be killed expectedly.
+ */
+static void do_shared(int shared_mode)
+{
+ int shm_id, sem_id, semaphore;
+ pid_t pid;
+ char *shared_page;
+ struct sembuf sembuffer;
+
+ if (shared_mode == MMAP_SHARED) {
+ shared_page = checked_mmap(NULL, PS, PROT_READ|PROT_WRITE,
+ MAP_SHARED|MAP_ANONYMOUS|MAP_POPULATE, 0, 0);
+ } else if (shared_mode == IPV_SHARED) {
+ shm_id = shmget(IPC_PRIVATE, PS, 0666|IPC_CREAT);
+ if (shm_id == -1)
+ err("shmget");
+ } else {
+ printf("XXX: invalid shared_mode\n");
+ return;
+ }
+
+ if (early_kill) {
+ sem_id = semget(IPC_PRIVATE, 1, 0666|IPC_CREAT);
+ if (sem_id == -1)
+ err("semget");
+ semaphore = semctl(sem_id, 0, SETVAL, 1);
+ if (semaphore == -1)
+ err("semctl");
+ if (get_semaphore(sem_id, &sembuffer))
+ err("get_semaphore");
+ }
+
+ pid = fork();
+ if (pid < 0)
+ err("fork");
+
+ if (shared_mode == IPV_SHARED) {
+ shared_page = shmat(shm_id, NULL, 0);
+ if (shared_page == (char *)-1)
+ err("shmat");
+ }
+
+ memset(shared_page, 'a', 3);
+
+ if (early_kill) {
+ struct sigaction sa = {
+ .sa_sigaction = sighandler,
+ .sa_flags = SA_SIGINFO
+ };
+ sigaction(SIGBUS, &sa, NULL);
+ expected_addr = shared_page;
+ }
+
+ if (pid) {
+ if (early_kill && sigsetjmp(early_recover_ctx, 1) == 0) {
+ if (put_semaphore(sem_id, &sembuffer))
+ err("get_semaphore");
+ /* waiting for SIGBUS from child */
+ sleep(10);
+ printf("XXX timeout: child process does not send signal.");
+ failure++;
+ return;
+ }
+ siginfo_t sig;
+ waitid(P_PID, pid, &sig, WEXITED);
+
+ /*
+ * check child termination status
+ * late kill : child should exit
+ * suicide version : child should be killed by signal
+ * early kill : child should be killed by signal
+ */
+ if (!early_kill) {
+ struct sigaction sigact;
+ sigaction(SIGBUS, NULL, &sigact);
+
+ if (sigact.sa_handler == SIG_DFL) {/* suicide version */
+ if (sig.si_code != CLD_KILLED)
+ goto child_error;
+ } else { /* late kill */
+ if (sig.si_code != CLD_EXITED)
+ goto child_error;
+ }
+ } else { /* early kill */
+ if (sig.si_code != CLD_EXITED)
+ goto child_error;
+ }
+
+ if (!early_kill)
+ recover("ipv shared page (parent)",
+ shared_page, MWRITE);
+
+ if (shared_mode == IPV_SHARED && shmdt(shared_page) == -1)
+ err("shmdt");
+ }
+
+ if (!pid) {
+ if (early_kill)
+ if (get_semaphore(sem_id, &sembuffer))
+ err("get_semaphore");
+ testmem("ipv shared page", shared_page, MWRITE);
+
+ if (shared_mode == IPV_SHARED && shmdt(shared_page) == -1)
+ err("shmdt");
+
+ _exit(0);
+ }
+
+ return;
+
+child_error:
+ printf("XXX child process was terminated unexpectedly\n");
+ failure++;
+ return;
+}
+
+static void mmap_shared(void)
+{
+ do_shared(MMAP_SHARED);
+}
+
+static void ipv_shared(void)
+{
+ do_shared(IPV_SHARED);
+}
struct testcase {
void (*f)(void);
@@ -512,6 +670,8 @@ struct testcase {
{ file_clean_mlocked, "file clean mlocked", 1 },
{ file_dirty_mlocked, "file dirty mlocked"},
{ nonlinear, "nonlinear" },
+ { mmap_shared, "mmap shared" },
+ { ipv_shared, "ipv shared" },
{}, /* dummy 1 for sniper */
{}, /* dummy 2 for sniper */
{}