/* Pre-requisites:-
*
* 1. Make sure that performance translators are switched off while running this
* test.
* 2. Perform the following volume set operation:
* # gluster volume set <VOLNAME> locks.mandatory-locking optimal
* 3. For installation under non-standard paths, export LD_LIBRARY_PATH to
* automatically load exact libgfapi.so and compile this C file as follows:
* $ gcc mandatory-lock-optimal.c -lgfapi -I <include path for api/glfs.h> -L
* <include path for libgfapi shared library>
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <glusterfs/api/glfs.h>
#define TOTAL_TEST_COUNT 8
/* C1 = Client 1 : C2 = Client 2 : C3 = Client 3 :
* fs1, fd1 are associated with C1. Similarly fs2, fd2 for C2
* and fs3, fd3 for C3 */
FILE *fp;
glfs_t *fs1, *fs2, *fs3;
glfs_fd_t *fd, *fd1, *fd2, *fd3;
struct flock lock;
char buf1[10], *buf2 = "ten bytes!", *fname = "/mand.lock";
int ret, test_count;
off_t offset;
/* run_test_1 () : C1 takes byte range mandatory read lock.
C2 attempts to read from a conflicting range.
Expected result : Read from C2 should pass.
* run_test_2 () : C1 takes byte range mandatory read lock.
C2 attempts write to a conflicting range.
Expected result : Write from C2 should fail with EAGAIN.
* run_test_3 () : C1 takes byte range advisory write lock.
C2 attempts to read from a conflicting range.
Expected result : Read from C2 should pass.
* run_test_4 () : C1 takes byte range advisory write lock.
C2 attempts write to a conflicting range.
Expected result : Write from C2 should pass.
* run_test_5 () : C1 takes byte range advisory read lock.
C2 attempts to open the same file with O_TRUNC.
Expected result : Open from C2 should pass.
* run_test_6 () : C1 takes byte range mandatory read lock.
C2 attempts to open the same file with O_TRUNC.
Expected result : Open from C2 should fail with EAGAIN.
* run_test_7 () : C1 takes byte range mandatory read lock.
C2 attempts ftruncate on a conflicting range.
Expected result : Write from C2 should fail with EAGAIN.
* run_test_8 () : C1 takes byte range advisory read lock.
C2 takes byte range mandatory read lock
within the byte range for which C1 already
holds an advisory lock so as to perform a
basic split/merge. C3 repositions fd3 to
start of C2's byte range mandatory lock
offset and attempts a write. Then it again
repositions fd3 to one byte past C2's byte
range mandatoy lock and again attempts a write.
Expected result : First write should fail with EAGAIN.
Second write should pass. */
#define LOG_ERR(func, err) \
do { \
if (!fp) \
fprintf(stderr, "\n%s : returned error (%s)\n", func, \
strerror(err)); \
else \
fprintf(fp, "\n%s : returned error (%s)\n", func, strerror(err)); \
cleanup_and_exit(err); \
} while (0)
void
cleanup_and_exit(int exit_status)
{
if (exit_status || test_count != TOTAL_TEST_COUNT) {
fprintf(fp, "\nAborting due to some test failures.\n");
exit_status = 1;
} else
fprintf(fp, "\nAll tests ran successfully.\n");
if (fp)
fclose(fp);
if (fd)
glfs_close(fd);
if (fd1)
glfs_close(fd1);
if (fd2)
glfs_close(fd2);
glfs_unlink(fs1, fname);
if (fs1)
glfs_fini(fs1);
if (fs2)
glfs_fini(fs2);
exit(exit_status);
}
glfs_t *
new_client_create(char *hostname, char *volname, char *logfile_name)
{
glfs_t *fs = NULL;
fs = glfs_new(volname);
if (!fs)
LOG_ERR("glfs_new", errno);
ret = glfs_set_volfile_server(fs, "tcp", hostname, 24007);
if (ret)
LOG_ERR("glfs_set_volfile_server", errno);
ret = glfs_set_logging(fs, logfile_name, 7);
if (ret)
LOG_ERR("glfs_set_logging", errno);
ret = glfs_init(fs);
if (ret)
LOG_ERR("glfs_init", errno);
return fs;
}
void
run_test_1(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
/* On successful read, 0 is returned as there is no content inside the
* file
*/
ret = glfs_read(fd2, buf1, 10, 0);
if (ret)
LOG_ERR("glfs_read", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_2(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_WRONLY | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
ret = glfs_write(fd2, buf2, 10, 0);
if (ret == 10 || errno != EAGAIN)
LOG_ERR("glfs_write", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_3(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_WRONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
/* Still there is no content inside file. So following read should
* return 0
*/
ret = glfs_read(fd2, buf1, 10, 0);
if (ret)
LOG_ERR("glfs_read", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_4(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_WRONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_WRLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_WRONLY | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
ret = glfs_write(fd2, buf2, 10, 0);
if (ret != 10)
LOG_ERR("glfs_write", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_5(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK | O_TRUNC);
if (!fd2)
LOG_ERR("glfs_open", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_6(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK | O_TRUNC);
if (fd2)
LOG_ERR("glfs_open", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_7(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 5L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_MANDATORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDWR | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
ret = glfs_ftruncate(fd2, 4, NULL, NULL);
if (ret == 0 || errno != EAGAIN)
LOG_ERR("glfs_ftruncate", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
void
run_test_8(int i)
{
fprintf(fp, "\nRunning Test-%d . . . ", i);
fd1 = glfs_open(fs1, fname, O_RDONLY | O_NONBLOCK);
if (!fd1)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 0L;
lock.l_len = 10L;
ret = glfs_file_lock(fd1, F_SETLK, &lock, GLFS_LK_ADVISORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd2 = glfs_open(fs2, fname, O_RDONLY | O_NONBLOCK);
if (!fd2)
LOG_ERR("glfs_open", errno);
lock.l_type = F_RDLCK;
lock.l_whence = SEEK_SET;
lock.l_start = 5L;
lock.l_len = 2L;
ret = glfs_file_lock(fd2, F_SETLK, &lock, GLFS_LK_MANDATORY);
if (ret)
LOG_ERR("glfs_file_lock", errno);
fd3 = glfs_open(fs3, fname, O_RDWR | O_NONBLOCK);
if (!fd3)
LOG_ERR("glfs_open", errno);
offset = glfs_lseek(fd3, 5L, SEEK_SET);
if (offset != 5)
LOG_ERR("glfs_lseek", errno);
ret = glfs_write(fd3, buf2, 10, 0);
if (ret == 10 || errno != EAGAIN)
LOG_ERR("glfs_write", errno);
offset = glfs_lseek(fd3, 8L, SEEK_SET);
if (offset != 8)
LOG_ERR("glfs_lseek", errno);
ret = glfs_write(fd3, buf2, 10, 0);
if (ret != 10)
LOG_ERR("glfs_write", errno);
ret = glfs_close(fd1);
if (ret)
LOG_ERR("glfs_close", errno);
fd1 = NULL;
ret = glfs_close(fd2);
if (ret)
LOG_ERR("glfs_close", errno);
fd2 = NULL;
ret = glfs_close(fd3);
if (ret)
LOG_ERR("glfs_close", errno);
fd3 = NULL;
test_count++;
fprintf(fp, "OK\n", i);
}
int
main(int argc, char *argv[])
{
char logfile[50];
if (argc != 4) {
fprintf(stderr,
"Usage: %s <server ip/hostname> <volume name> <test log "
"directory>\n",
argv[0]);
return 0;
}
sprintf(logfile, "%s/%s", argv[3], "mandatory-lock-optimal-test.log");
fp = fopen(logfile, "w");
if (!fp) {
fprintf(stderr, "\n%s\n", logfile);
LOG_ERR("Log file creation", errno);
}
sprintf(logfile, "%s/%s", argv[3], "glfs-client-1.log");
fs1 = new_client_create(argv[1], argv[2], logfile);
if (!fs1)
LOG_ERR("client-1 creation", EINVAL);
sprintf(logfile, "%s/%s", argv[3], "glfs-client-2.log");
fs2 = new_client_create(argv[1], argv[2], logfile);
if (!fs2)
LOG_ERR("client-2 creation", EINVAL);
sprintf(logfile, "%s/%s", argv[3], "glfs-client-3.log");
fs3 = new_client_create(argv[1], argv[2], logfile);
if (!fs3)
LOG_ERR("client-3 creation", EINVAL);
fd = glfs_creat(fs1, fname, O_RDWR, 0644);
if (!fd)
LOG_ERR("glfs_creat", errno);
test_count = 0;
run_test_1(1);
run_test_2(2);
run_test_3(3);
run_test_4(4);
run_test_5(5);
run_test_6(6);
run_test_7(7);
run_test_8(8);
cleanup_and_exit(0);
return 0;
}