/* * Copyright (c) 2010 David Teigland * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License V2 * as published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libdlm.h" /* * The general idea of this test is * - dlm_lock on node1 gets EX * - dlm_lock on node2 blocks on EX * - dlm_lock on node1 is killed * - dlm_lock on node2 should get EX * repeat * * The dlm_lock process is intentionally killed without an explicit * unlock to test the lock cleanup done by the kernel when a process * exits while holding locks. */ struct dlm_lksb lksb; static int ast_called = 0; static void bast_fn(void *arg) { printf("loop bast\n"); } static void ast_fn(void *arg) { printf("loop ast\n"); ast_called = 1; } static int poll_for_ast(void) { struct pollfd pfd; pfd.fd = dlm_get_fd(); pfd.events = POLLIN; while (!ast_called) { if (poll(&pfd, 1, 0) < 0) { perror("poll"); return -1; } dlm_dispatch(pfd.fd); } ast_called = 0; return 0; } static int rand_int(int a, int b) { return a + (int) (((float)(b - a + 1)) * random() / (RAND_MAX+1.0)); } #define LINE_LEN 64 static int wait_child_lock(int pr_fd) { char *done_str = "dlm_lock convert EX done"; char line[LINE_LEN], prog[32], act[32], mode[32], done[32], status[32]; FILE *file; int n, val, rv = -1; file = fdopen(pr_fd, "r"); if (!file) { printf("loop: fdopen error %d\n", errno); return -1; } while (fgets(line, LINE_LEN, file)) { printf("%s", line); fflush(stdout); n = sscanf(line, "%s %s %s %s %s %d", prog, act, mode, done, status, &val); if (n < 6) continue; if (!strncmp(line, done_str, strlen(done_str))) { if (!strcmp(status, "status") && val == 0) rv = 0; break; } } fclose(file); return rv; } int main(int argc, char *argv[]) { int fda[2]; int pr_fd, cw_fd; /* parent read fd, child write fd */ int pid, status, n, rv; char *name = "dlm_lock_loop"; printf("loop pid %d", getpid()); printf("loop resource %s\n", name); printf("loop request NL ...\n"); rv = dlm_lock(LKM_NLMODE, &lksb, 0, name, strlen(name), 0, ast_fn, &lksb, bast_fn, NULL); if (rv < 0) { printf("loop request NL done error %d %d", rv, errno); return -1; } poll_for_ast(); printf("loop request NL done status %d lkid %x\n", lksb.sb_status, lksb.sb_lkid); while (1) { pipe(fda); pr_fd = fda[0]; cw_fd = fda[1]; pid = fork(); if (!pid) { /* child's stdout and stderr sent to parent's pr_fd */ close(STDOUT_FILENO); dup(cw_fd); close(STDERR_FILENO); dup(cw_fd); close(STDIN_FILENO); execl("./dlm_lock", "./dlm_lock", "2", NULL); exit(EXIT_FAILURE); } else { printf("loop fork pid %d\n", pid); /* wait for child to get first lock EX */ printf("loop wait child lock\n"); rv = wait_child_lock(pr_fd); close(pr_fd); close(cw_fd); if (rv < 0) { printf("loop child lock error\n"); break; } /* sleep random number of seconds */ n = rand_int(0, 4); printf("loop sleep %d\n", n); sleep(n); /* kill child */ printf("loop kill pid %d\n", pid); kill(pid, SIGKILL); /* wait for child to exit */ printf("loop wait pid %d\n", pid); waitpid(pid, &status, 0); /* sleep random number of seconds */ n = rand_int(0, 2); printf("loop sleep %d\n", n); sleep(n); } } return 0; }