Viewing: parallel_grouplock.c
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
*
* lustre/tests/parallel_grouplock.c
*
* Author: You Feng <youfeng@clusterfs.com>
*/
#include <limits.h>
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <asm/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include "lp_utils.h"
#define LPGL_BUF_LEN 8192
#define LPGL_TEST_ITEMS 12
#define MIN_GLHOST 5
#define MAX_WAIT_TRIES 10
#define WAIT_TIME 1 /* secs */
#define ONE_MB 1048576 /* 1 MB */
#define MIN_LGBUF_SIZE 536870912 /* 512 MB */
#define MAX_LGBUF_SIZE 536870912 /* 512 MB */
// #define MAX_LGBUF_SIZE 1073741824 /* 1 GB */
#define READ 1
#define WRITE 2
#define IOCTL 3
#define CLOSE 4
int rank;
int size;
char *testdir;
int only_test;
char buf[LPGL_BUF_LEN];
char *lgbuf;
int lgbuf_size;
char filename[MAX_FILENAME_LEN];
static void
alloc_lgbuf()
{
if (lgbuf)
return;
lgbuf_size = MAX_LGBUF_SIZE;
for (; lgbuf_size >= MIN_LGBUF_SIZE; lgbuf_size -= ONE_MB)
if ((lgbuf = (char *)malloc(lgbuf_size)) != NULL)
return;
FAIL("malloc of large buffer failed.\n");
}
static inline void
read_buf(int fd)
{
int pos, rc;
rc = read(fd, buf, sizeof(buf));
if (rc == -1) {
pos = lseek(fd, 0, SEEK_CUR);
FAILF("read of file %s at pos %d for %zu bytes returned %d: (%d) %s.\n",
filename, pos, sizeof(buf), rc, errno, strerror(errno));
} else if (rc != sizeof(buf)) {
pos = lseek(fd, 0, SEEK_CUR);
FAILF("read of file %s at pos %d for %zu bytes returned %d.\n",
filename, pos, sizeof(buf), rc);
}
}
static inline void
write_buf(int fd, int index)
{
int pos = index * sizeof(buf);
int rc;
memset(buf, index, sizeof(buf));
lseek(fd, pos, SEEK_SET);
rc = write(fd, buf, sizeof(buf));
if (rc == -1)
FAILF("write of file %s at pos %d for %zu bytes returned %d: (%d) %s.\n",
filename, pos, sizeof(buf), rc, errno, strerror(errno));
else if (rc != sizeof(buf))
FAILF("write of file %s at pos %d for %zu bytes returned %d.\n",
filename, pos, sizeof(buf), rc);
}
/*
* task0 attempts GR(gid=1) -- granted immediately
* task1 attempts PR|PW -- blocked, goes on waiting list
* task2 attempts GR(gid=1) -> should be granted
* task2 writes to file and releases GR(gid=1)
* task0 waits for task2 to complete its processing
* task0 writes to file and releases GR(gid=1)
* task1 PR|PW should be granted and reads the file
*/
void grouplock_test1(char *filename, int fd, int blocking_op, int unlock_op)
{
MPI_Request req1, req2;
int iter, flag1, flag2, temp1, temp2;
int i, rc, gid = 1;
if (rank == 0) {
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
}
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 1:
if (blocking_op == WRITE) {
write_buf(fd, rank);
lseek(fd, 0, SEEK_SET);
}
for (i = 0; i <= 2; i++)
read_buf(fd);
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 2:
/* Wait for task1 to progress. This could be racey. */
sleep(WAIT_TIME);
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
write_buf(fd, rank);
if (unlock_op == CLOSE)
rc = close(fd);
else
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
(unlock_op == CLOSE) ? "close" : "ioctl",
filename, errno, strerror(errno));
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 0:
/* PR|PW task will tell us when it completes */
MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
/* 2nd locking task will tell us when it completes */
MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
/* Wait for task2 to complete. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter)
FAIL("2nd locking task is not progressing\n");
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
if (flag1)
FAIL("PR|PW task progressed even though GROUP lock is held\n");
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
} while (!flag2);
/* Make sure task1 is still waiting. */
iter = MAX_WAIT_TRIES;
do {
iter--;
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
if (flag1)
FAIL("PR|PW task progressed even though GROUP lock is held\n");
} while (iter);
write_buf(fd, rank);
/* Now we need to release the lock */
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_UNLOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
/* Wait for task1 to complete. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter) {
FAIL("PR|PW task is not progressing even though GROUP lock was released\n");
break;
}
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
} while (!flag1);
break;
}
}
/*
* task0 attempts GR(gid=1) -- granted immediately
* task1 attempts GR(gid=2) -- blocked
* task2 attempts PR|PW -- blocked
* task3 attempts GR(gid=2) -- blocked
* task4 attempts GR(gid=1) -- should be granted
* task0,4 writes to file and releases GR(gid=1) --
* this allows task2 & 3's GR locks to be granted; task4 remains blocked.
* task1 & 3 write to file and release GR(gid=2)
* task2 PR|PW should be granted and reads the file.
*/
void grouplock_test2(char *filename, int fd, int blocking_op, int unlock_op)
{
int i, iter, rc, gid = 1;
int flag1, flag2, flag3, flag4;
int temp1, temp2, temp3, temp4;
MPI_Request req1, req2, req3, req4;
if (rank == 0) {
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
}
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 3:
/* Wait for task2 to issue its read request. */
sleep(2 * WAIT_TIME);
case 1:
gid = 2;
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
write_buf(fd, rank);
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
/*
* Do not release the locks until task 0 is ready to watch
* for reading task only
*/
MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
if (unlock_op == CLOSE)
rc = close(fd);
else
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
(unlock_op == CLOSE) ? "close" : "ioctl",
filename, errno, strerror(errno));
break;
case 2:
/* Give task1 a chance to request its GR lock. */
sleep(WAIT_TIME);
if (blocking_op == WRITE) {
write_buf(fd, rank);
lseek(fd, 0, SEEK_SET);
}
for (i = 0; i <= 3; i++)
read_buf(fd);
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 4:
/* Give task1 & 3 a chance to queue their GR locks. */
sleep(3 * WAIT_TIME);
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
write_buf(fd, rank);
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("%s release GROUP_LOCK of file %s: (%d) %s.\n",
(unlock_op == CLOSE) ? "close" : "ioctl",
filename, errno, strerror(errno));
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 0:
/* locking tasks will tell us when they complete */
MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
MPI_Irecv(&temp3, 1, MPI_INT, 3, 1, MPI_COMM_WORLD, &req3);
MPI_Irecv(&temp4, 1, MPI_INT, 4, 1, MPI_COMM_WORLD, &req4);
/* Make sure all tasks that should be blocked are waiting. */
iter = MAX_WAIT_TRIES;
do {
iter--;
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
if (flag1 || flag3)
FAIL("GROUP (gid=2) task progressed even though GROUP (gid=1) lock is held.\n");
if (flag2)
FAIL("PR|PW task progressed even though GROUP (gid=1) lock is still held\n");
} while (iter);
/* Wait for task4 to signal it has completed. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter)
FAIL("2nd task GROUP(gid=1) not progressing\n");
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
MPI_Test(&req4, &flag4, MPI_STATUS_IGNORE);
if (flag1 || flag3)
FAIL("GROUP (gid=2) task progressed even though GROUP (gid=1) lock is held.\n");
if (flag2)
FAIL("PR|PW task progressed even though GROUP (gid=1) lock is still held\n");
} while (!flag4);
write_buf(fd, rank);
/* Now let's release first lock */
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_UNLOCK of file %s returned %d",
filename, rc);
/* Wait for task1 & 3 to signal they have their lock. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter)
FAIL("GROUP(gid=2) tasks not progressing\n");
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
if (flag2) {
fprintf(stderr, "task2 %d\n", flag2);
FAIL("PR task progressed even though GROUP lock was on the queue task\n");
}
} while (!(flag1 && flag3));
/* Make sure task2 is still waiting. */
iter = MAX_WAIT_TRIES;
do {
iter--;
sleep(WAIT_TIME);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
if (flag2)
FAIL("PR task progressed even though GR(gid=2) lock was active.\n");
} while (iter);
/* Tell task1 & 3 to release their GR(gid=2) lock. */
MPI_Send(&gid, 1, MPI_INT, 1, 1, MPI_COMM_WORLD);
MPI_Send(&gid, 1, MPI_INT, 3, 1, MPI_COMM_WORLD);
/* Wait for task2 (PR) to complete. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter) {
FAIL("reading task is not progressing even though GROUP locks are released\n");
break;
}
sleep(WAIT_TIME);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
} while (!flag3);
break;
}
}
/*
* Tests a bug that once existed in the group lock code;
* i.e. that a GR lock request on a O_NONBLOCK fd could fail even though
* there is no blocking GROUP lock ahead of it on the waitq.
*
* task0 starts a large write (PW). this test could be racey if this
* write finishes too quickly.
* task1 attempts GR(gid=1) -- blocked
* task2 attempts GR(gid=2) with a O_NONBLOCK fs. should not fail.
*/
void grouplock_test3(char *filename, int fd)
{
MPI_Request req1, req2;
int iter, flag1, flag2, temp1, temp2;
int rc, gid = 1;
if (rank == 0) {
alloc_lgbuf();
} else if (rank == 2) {
rc = fcntl(fd, F_SETFL, O_NONBLOCK);
if (rc == -1)
FAILF("fcntl(O_NONBLOCK) failed: (%d) %s.\n",
errno, strerror(errno));
}
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 2:
gid = 2;
usleep(10000);
usleep(10000);
case 1:
/*
* Racey, we have to sleep just long enough for
* task0's write to start.
*/
usleep(10000);
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
/* tell task0 we have the lock. */
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
/* the close of fd will release the lock. */
break;
case 0:
rc = write(fd, lgbuf, lgbuf_size);
if (rc == -1)
FAILF("write of file %s for %d bytes returned %d: (%d) %s.\n",
filename, lgbuf_size, rc, errno, strerror(errno));
else if (rc != lgbuf_size)
FAILF("write of file %s for %d bytes returned %d.\n",
filename, lgbuf_size, rc);
/* GR tasks will tell us when they complete */
MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
/* Wait for task1 & 2 to complete. */
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter) {
FAIL("GR(gid=1) tasks are not progressing even no conflicting locks exist.\n");
break;
}
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
} while (!(flag1 && flag2));
break;
}
}
/*
* Tests a bug that once existed in the group lock code;
* i.e. extent locks without O_NONBLOCK that go on the waitq before a group
* lock request came in and was granted. The extent lock would timed out and
* produce an error.
*
* task0 starts a large write (PW). this test could be racey if this
* write finishes too quickly.
* task1 attempts PR -- blocked
* task2 attempts GR(gid=1) -- blocked
* task0 completes write
* task1 should wakeup and complete its read
* task2 should wakeup and after task1 complete.
*/
void grouplock_test4(char *filename, int fd)
{
MPI_Request req1;
int iter, flag1, temp1;
int rc, gid = 1;
if (rank == 0)
alloc_lgbuf();
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 1:
/*
* Racey, we have to sleep just long enough for
* task0's write to start.
*/
MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
/* tell task2 to go. */
MPI_Send(&gid, 1, MPI_INT, 2, 1, MPI_COMM_WORLD);
sleep(WAIT_TIME);
read_buf(fd);
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 2:
/* Give task0 & 1 a chance to start. */
MPI_Recv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
sleep(2 * WAIT_TIME);
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
/* tell task0 we have the lock. */
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
/*
* Do not release the locks until task 0 tells us too.
* for reading task only
*/
MPI_Recv(&temp1, 1, MPI_INT, 0, 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_UNLOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
break;
case 0:
/* tell task1 to go to avoid race */
MPI_Send(&gid, 1, MPI_INT, 1, 1, MPI_COMM_WORLD);
rc = write(fd, lgbuf, lgbuf_size);
if (rc == -1)
FAILF("write of file %s for %d bytes returned %d: (%d) %s.\n",
filename, lgbuf_size,
rc, errno, strerror(errno));
else if (rc != lgbuf_size)
FAILF("write of file %s for %d bytes returned %d.\n",
filename, lgbuf_size, rc);
/* wait for task2 to get its lock. */
MPI_Recv(&temp1, 1, MPI_INT, 2, 1, MPI_COMM_WORLD,
MPI_STATUS_IGNORE);
/* Tell task2 it's ok to release its GR(gid=1) lock. */
MPI_Send(&gid, 1, MPI_INT, 2, 1, MPI_COMM_WORLD);
/* wait a really long time. */
sleep(180 * WAIT_TIME);
/* PR task will tell us when it completes */
MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
/*
* Make sure the PR task is successful and doesn't hang.
*
* XXX - To test properly we need to make sure the read
* gets queued before task2's group lock request.
* You may need to increase lgbuf_size.
*/
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter) {
FAIL("PR task is hung !\n");
break;
}
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
} while (!flag1);
break;
}
}
/*
* task0 attempts GR(gid=1) -- granted
* task1 attempts PR on non-blocking fd -> should return -EAGAIN
* task2 attempts PW on non-blocking fd -> should return -EAGAIN
* task3 attempts GR(gid=2) on non-blocking fd -> should return -EAGAIN
*/
void grouplock_nonblock_test(char *filename, int fd)
{
MPI_Request req1, req2, req3;
int iter, flag1, flag2, flag3, temp1, temp2, temp3;
int rc, gid = 1;
if (rank == 0) {
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
}
rc = fcntl(fd, F_SETFL, O_NONBLOCK);
if (rc == -1)
FAILF("fcntl(O_NONBLOCK) failed: (%d) %s.\n",
errno, strerror(errno));
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 1:
rc = read(fd, buf, sizeof(buf));
if ((rc != -1) || (errno != EAGAIN))
FAIL("PR lock succeeded while incompatible GROUP LOCK (gid=1) is still held\n");
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 2:
rc = write(fd, buf, sizeof(buf));
if ((rc != -1) || (errno != EAGAIN))
FAIL("PW lock succeeded while incompatible GROUP LOCK (gid=1) is still held\n");
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 3:
gid = 2;
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if ((rc != -1) || (errno != EAGAIN))
FAIL("GROUP_LOCK (gid=2) succeeded while incompatible GROUP LOCK (gid=1) is still held.\n");
MPI_Send(&gid, 1, MPI_INT, 0, 1, MPI_COMM_WORLD);
break;
case 0:
/* reading task will tell us when it completes */
MPI_Irecv(&temp1, 1, MPI_INT, 1, 1, MPI_COMM_WORLD, &req1);
/* writing task will tell us when it completes */
MPI_Irecv(&temp2, 1, MPI_INT, 2, 1, MPI_COMM_WORLD, &req2);
/* 2nd locking task will tell us when it completes */
MPI_Irecv(&temp3, 1, MPI_INT, 3, 1, MPI_COMM_WORLD, &req3);
iter = MAX_WAIT_TRIES;
do {
iter--;
if (!iter)
FAIL("non-blocking tasks are not progressing\n");
sleep(WAIT_TIME);
MPI_Test(&req1, &flag1, MPI_STATUS_IGNORE);
MPI_Test(&req2, &flag2, MPI_STATUS_IGNORE);
MPI_Test(&req3, &flag3, MPI_STATUS_IGNORE);
} while (!(flag1 && flag2 && flag3));
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_UNLOCK of file %s", filename);
break;
}
}
/* Just test some error paths with invalid requests */
void grouplock_errorstest(char *filename, int fd)
{
int rc, gid = 1;
MPI_Barrier(MPI_COMM_WORLD);
switch (rank) {
case 0:
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_LOCK of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
/* second group lock on same fd, same gid */
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
if (rc == -1) {
if (errno != EINVAL)
FAILF("Double GROUP lock failed with errno %d instead of EINVAL\n",
errno);
} else {
FAIL("Taking second GROUP lock on same fd succeed\n");
}
/* second group lock on same fd, different gid */
rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid + 1);
if (rc == -1) {
if (errno != EINVAL)
FAILF("Double GROUP lock with different gid failed with errno %d instead of EINVAL\n",
errno);
} else {
FAIL("Taking second GROUP lock on same fd, with different gid, succeeded.\n");
}
/* GROUP unlock with wrong gid */
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid + 1);
if (rc == -1) {
if (errno != EINVAL)
FAILF("GROUP_UNLOCK with wrong gid failed with errno %d instead of EINVAL\n",
errno);
} else {
FAIL("GROUP unlock with wrong gid succeed\n");
}
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1)
FAILF("ioctl GROUP_UNLOCK of file %s returned %d.",
filename, rc);
break;
case 1:
/* unlock of never locked fd */
rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
if (rc == -1) {
if (errno != EINVAL)
FAILF("GROUP_UNLOCK on never locked fd failed with errno %d instead of EINVAL.\n",
errno);
} else {
FAIL("GROUP unlock on never locked fd succeed\n");
}
break;
}
}
void grouplock_file(char *name, int subtest)
{
int fd;
int flags = O_CREAT | O_RDWR | O_SYNC | O_TRUNC;
int mode = 0666;
sprintf(filename, "%s/%s", testdir, name);
fd = open(filename, flags, mode);
if (fd == -1)
FAILF("open of file %s: (%d) %s.\n",
filename, errno, strerror(errno));
MPI_Barrier(MPI_COMM_WORLD);
switch (subtest) {
case 1:
grouplock_test1(filename, fd, READ, IOCTL);
break;
case 2:
grouplock_test1(filename, fd, READ, CLOSE);
break;
case 3:
grouplock_test1(filename, fd, WRITE, IOCTL);
break;
case 4:
grouplock_test1(filename, fd, WRITE, CLOSE);
break;
case 5:
grouplock_test2(filename, fd, READ, IOCTL);
break;
case 6:
grouplock_test2(filename, fd, READ, CLOSE);
break;
case 7:
grouplock_test2(filename, fd, WRITE, IOCTL);
break;
case 8:
grouplock_test2(filename, fd, WRITE, CLOSE);
break;
case 9:
grouplock_nonblock_test(filename, fd);
break;
case 10:
grouplock_errorstest(filename, fd);
break;
case 11:
grouplock_test3(filename, fd);
break;
case 12:
grouplock_test4(filename, fd);
break;
default:
FAILF("wrong subtest number %d (should be <= %d)",
subtest, LPGL_TEST_ITEMS);
}
close(fd);
if (rank == 0)
unlink(filename);
MPI_Barrier(MPI_COMM_WORLD);
}
void parallel_grouplock(void)
{
char teststr[16];
int i;
if (only_test) {
sprintf(teststr, "subtest %d", only_test);
begin(teststr);
grouplock_file("parallel_grouplock", only_test);
end(teststr);
} else {
for (i = 1; i <= LPGL_TEST_ITEMS; i++) {
sprintf(teststr, "subtest %d", i);
begin(teststr);
grouplock_file("parallel_grouplock", i);
end(teststr);
}
}
}
void usage(char *proc)
{
int i;
if (rank == 0) {
printf("Usage: %s [-h] -d <testdir> [-n <num>]\n", proc);
printf(" [-t <num>] [-v] [-V #] [-g]\n");
printf("\t-h: prints this help message\n");
printf("\t-d: the directory in which the tests will run\n");
printf("\t-n: repeat test # times\n");
printf("\t-t: run a particular test #\n");
printf("\t-v: increase the verbositly level by 1\n");
printf("\t-V: select a specific verbosity level\n");
printf("\t-g: debug mode\n");
}
MPI_Initialized(&i);
if (i)
MPI_Finalize();
exit(0);
}
int main(int argc, char *argv[])
{
int i, iterations = 1, c;
setbuf(stdout, 0);
setbuf(stderr, 0);
/*
* Check for -h parameter before MPI_Init so the binary can be
* called directly, without, for instance, mpirun
*/
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help"))
usage(argv[0]);
}
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
/* Parse command line options */
while (1) {
c = getopt(argc, argv, "d:ghn:t:vV:");
if (c == -1)
break;
switch (c) {
case 'd':
testdir = optarg;
break;
case 'g':
debug = 1;
break;
case 'h':
usage(argv[0]);
break;
case 'n':
iterations = atoi(optarg);
break;
case 't':
only_test = atoi(optarg);
break;
case 'v':
verbose += 1;
break;
case 'V':
verbose = atoi(optarg);
break;
}
}
if (rank == 0)
printf("%s is running with %d task(es) %s\n",
argv[0], size, debug ? "in DEBUG mode" : "\b\b");
if (size < MIN_GLHOST) {
fprintf(stderr,
"Error: %d tasks run, but should be at least %d tasks to run the test!\n",
size, MIN_GLHOST);
MPI_Abort(MPI_COMM_WORLD, 2);
}
if (!testdir && rank == 0) {
fprintf(stderr,
"Please specify a test directory! (\"%s -h\" for help)\n",
argv[0]);
MPI_Abort(MPI_COMM_WORLD, 2);
}
lp_gethostname();
for (i = 0; i < iterations; ++i) {
if (rank == 0)
printf("%s: Running test #%s(iter %d)\n",
timestamp(), argv[0], i);
parallel_grouplock();
MPI_Barrier(MPI_COMM_WORLD);
}
if (rank == 0)
printf("%s: All tests passed!\n", timestamp());
MPI_Finalize();
return 0;
}