This test forks off several children in various states to ensure that the IPC namespace information is properly restored after restart. Cc: orenl@xxxxxxxxxxxxxxx Signed-off-by: Dan Smith <danms@xxxxxxxxxx> --- Makefile | 2 +- tst_ipcshm_multi.c | 266 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 267 insertions(+), 1 deletions(-) create mode 100644 tst_ipcshm_multi.c diff --git a/Makefile b/Makefile index c847a0c..2da03bb 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ CFLAGS += -g $(WARNS) $(PATHS) $(DEBUG) PROGS = self ckpt rstr mktree TESTS= tst_onetask tst_multitask tst_bigmem tst_pipes tst_pipes2 tst_shmem \ - tst_ipcshm tst_ipcmsq + tst_ipcshm tst_ipcmsq tst_ipcshm_multi LDLIBS = -lm diff --git a/tst_ipcshm_multi.c b/tst_ipcshm_multi.c new file mode 100644 index 0000000..1ef31f7 --- /dev/null +++ b/tst_ipcshm_multi.c @@ -0,0 +1,266 @@ +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include <sys/ipc.h> +#include <sys/shm.h> + +#include <linux/sched.h> +#include <sched.h> + +#define OUTFILE "/tmp/cr-test.out" +#define SEG_SIZE (20 * 4096) +#define DELAY 20 + +int attach(unsigned char **seg, int num) +{ + int id; + + id = shmget(123, SEG_SIZE, 0700|IPC_EXCL); + if (id < 0) { + printf("[CHILD %i] shmget: %m\n", num); + return -1; + } + + *seg = shmat(id, NULL, 0); + if (!*seg) { + printf("[CHILD %i] shmat: %m\n", num); + return -1; + } + + printf("[CHILD %i] Attached\n", num); + + return 0; +} + +int validate(unsigned char *seg, int num) +{ + int i; + + for (i = 1; i < SEG_SIZE; i++) { + if (seg[i] != (unsigned char)(i % 256)) { + printf("[CHILD %i] Mismatch at %hhu: %hhu\n", + num, i, seg[i]); + return -1; + } + } + + printf("[CHILD %i] Validated\n", num); + + return 0; +} + +void track(unsigned char *seg, int num) +{ + int i; + + for (i = 0; i < 20; i++) { + printf("[CHILD %i] Seg[0]: %i\n", num, seg[0]); + sleep(1); + } +} + +/* + * Attach to the shared segment *before* the checkpoint and then track + * the changing seg[0] position afterwards. + */ +int child1(void) +{ + unsigned char *seg; + int num = 1; + + printf("[CHILD %i] Running\n", num); + + sleep(1); /* Allow master to finish initializing the array */ + + if (attach(&seg, num)) + return -1; + + if (validate(seg, num)) + return -1; + + sleep(DELAY - 1); /* Wait until after the checkpoint */ + + track(seg, num); + + return 0; +} + +/* + * Attempt to attach to the shared segment *after* the checkpoint to + * verify that things are hooked up properly after restart by tracking + * seg[0]. + */ +int child2(void) +{ + unsigned char *seg; + int num = 2; + + printf("[CHILD %i] Running\n", num); + + sleep(DELAY); /* Wait until after the checkpoint */ + + if (attach(&seg, num)) + return -1; + + if (validate(seg, num)) + return -1; + + track(seg, num); + + return 0; +} + +int child4(void); + +/* + * Detach from the parent's IPC namespace and verify that: + * 1. We can't attach to the parent's segment + * 2. We can create our own of the same ID without conflict + * 3. We do not see the parent's changing seg[0] after restart + */ +int child3(void) +{ + unsigned char *seg; + int num = 3; + + if (unshare(CLONE_NEWIPC) != 0) { + printf("[CHILD %i] unshare(CLONE_NEWIPC): %m", num); + return -1; + } + + if (fork() == 0) + return child4(); + + printf("[CHILD %i] Running (new IPC NS)\n", num); + + printf("[CHILD %i] Attempting parent attach (should fail)\n", num); + if (!attach(&seg, num)) { + printf("[CHILD %i] Attached to parent's IPC!\n", num); + return -1; + } + + if (shmget(123, SEG_SIZE, 0700|IPC_CREAT|IPC_EXCL) < 0) { + printf("[CHILD %i] Failed to create shm in namespace: %m\n", + num); + return -1; + } + + if (attach(&seg, num)) + return -1; + + seg[0] = 123; + + sleep(DELAY); /* Wait until after checkpoint, then attach */ + + track(seg, num); + + return 0; +} + +/* + * This child is forked from child3 under the new IPC namespace. + * Verify that post-restart, we do not see the changing seg[0] + */ +int child4(void) +{ + unsigned char *seg; + int num = 4; + + printf("[CHILD %i] Running (new IPC NS)\n", num); + + sleep(DELAY); /* Wait past my parent creating the IPC */ + + if (attach(&seg, num)) + return -1; + + track(seg, num); + + return 0; +} + +void shm_destroy(void) +{ + int id; + + id = shmget(123, SEG_SIZE, 0700); + if (id < 0) + return; + + if (shmctl(id, IPC_RMID, NULL) == 0) + printf("Deleted SHM %i\n", id); +} + +int main(int argc, char *argv[]) +{ + int id; + unsigned char *seg; + int i; + int pid1, pid2, pid3; +#ifndef TEST + FILE *file; + + close(0); + close(1); + close(2); + + unlink(OUTFILE); + file = fopen(OUTFILE, "w+"); + if (!file) { + perror("open"); + exit(1); + } + if (dup2(0,2) < 0) { + perror("dup2"); + exit(2); + } + stdout = file; + setlinebuf(file); +#endif + shm_destroy(); + + pid1 = fork(); + if (pid1 == 0) + return child1(); + + pid2 = fork(); + if (pid2 == 0) + return child2(); + + pid3 = fork(); + if (pid3 == 0) + return child3(); + + id = shmget(123, SEG_SIZE, 0700|IPC_CREAT|IPC_EXCL); + if (id < 0) { + perror("shmget"); + exit(1); + } + + seg = (unsigned char *) shmat(id, NULL, 0); + if(seg == ((void *) -1)) { + perror("shmat"); + exit(1); + } + + for (i = 0; i < SEG_SIZE; i++) + seg[i] = i; + + printf("[MSTER] Waiting for checkpoint\n"); + sleep(DELAY); + printf("[MSTER] Woke\n"); + + for (i = 0; i < 15; i++) { + seg[0] = i; + sleep(1); + } + + if (shmdt(seg) < 0) + perror("shmdt"); + + shm_destroy(); + + printf("[MSTER] Completed\n"); + + return 0; +} -- 1.6.0.3 _______________________________________________ Containers mailing list Containers@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linux-foundation.org/mailman/listinfo/containers