summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorAnoop C S <anoopcs@redhat.com>2016-01-19 14:35:18 +0530
committerNiels de Vos <ndevos@redhat.com>2018-01-22 09:54:02 +0000
commitec3df9e65a3a2e1005cd4d50d06a8819fd3ab5f6 (patch)
tree847ac98b10927e4e1081ba35260beb4b18996d47 /tests
parent10d74166f17fa44c06bd1357e0a4b0b052265425 (diff)
downloadglusterfs-ec3df9e65a3a2e1005cd4d50d06a8819fd3ab5f6.tar.gz
glusterfs-ec3df9e65a3a2e1005cd4d50d06a8819fd3ab5f6.tar.xz
glusterfs-ec3df9e65a3a2e1005cd4d50d06a8819fd3ab5f6.zip
libgfapi: Add new api for supporting mandatory-locks
The current API for byte-range locks [glfs_posix_lock()] doesn't allow applications to specify whether it is advisory or mandatory type locks. This particular change is to introduce an extended byte-range lock API with an additional argument for including the byte-range lock mode to be one among advisory(default) or mandatory. Patch also includes a gfapi test case which make use of this new api to acquire mandatory locks. Ref: https://github.com/gluster/glusterfs-specs/blob/master/done/GlusterFS%203.8/Mandatory%20Locks.md Change-Id: Ia09042c755d891895d96da857321abc4ce03e20c Updates #393 Signed-off-by: Anoop C S <anoopcs@redhat.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/basic/gfapi/Makefile3
-rw-r--r--tests/basic/gfapi/mandatory-lock-optimal.c503
-rw-r--r--tests/basic/gfapi/mandatory-lock-optimal.t38
3 files changed, 543 insertions, 1 deletions
diff --git a/tests/basic/gfapi/Makefile b/tests/basic/gfapi/Makefile
index e30fefea5b..1c5cf03ca3 100644
--- a/tests/basic/gfapi/Makefile
+++ b/tests/basic/gfapi/Makefile
@@ -5,7 +5,8 @@ CFLAGS = -Wall -g $(shell pkg-config --cflags glusterfs-api)
LDFLAGS = $(shell pkg-config --libs glusterfs-api)
BINARIES = upcall-cache-invalidate libgfapi-fini-hang anonymous_fd seek \
- bug1283983 bug1291259 gfapi-ssl-test gfapi-load-volfile
+ bug1283983 bug1291259 gfapi-ssl-test gfapi-load-volfile \
+ mandatory-lock-optimal
%: %.c
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^
diff --git a/tests/basic/gfapi/mandatory-lock-optimal.c b/tests/basic/gfapi/mandatory-lock-optimal.c
new file mode 100644
index 0000000000..6c62f437a0
--- /dev/null
+++ b/tests/basic/gfapi/mandatory-lock-optimal.c
@@ -0,0 +1,503 @@
+/* Pre-requisites:-
+ *
+ * 1. Make sure that peformance 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);
+ 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;
+}
diff --git a/tests/basic/gfapi/mandatory-lock-optimal.t b/tests/basic/gfapi/mandatory-lock-optimal.t
new file mode 100644
index 0000000000..27062e1f6c
--- /dev/null
+++ b/tests/basic/gfapi/mandatory-lock-optimal.t
@@ -0,0 +1,38 @@
+#!/bin/bash
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+
+cleanup
+
+TEST glusterd
+
+# Create and start the volume
+TEST $CLI volume create $V0 $H0:$B0/${V0}1
+TEST $CLI volume start $V0
+
+logdir=`gluster --print-logdir`
+
+# Switch off performance translators
+TEST $CLI volume set $V0 performance.open-behind off
+TEST $CLI volume set $V0 performance.write-behind off
+TEST $CLI volume set $V0 performance.quick-read off
+TEST $CLI volume set $V0 performance.io-cache off
+TEST $CLI volume set $V0 performance.read-ahead off
+TEST $CLI volume set $V0 performance.readdir-ahead off
+
+# Enable optimal mandatory-locking mode and restart the volume
+TEST $CLI volume set $V0 locks.mandatory-locking optimal
+TEST $CLI volume stop $V0
+TEST $CLI volume start $V0
+
+# Compile and run the test program
+TEST build_tester $(dirname $0)/mandatory-lock-optimal.c -lgfapi
+TEST ./$(dirname $0)/mandatory-lock-optimal $H0 $V0 $logdir
+
+# Cleanup the environment
+cleanup_tester $(dirname $0)/mandatory-lock-optimal
+TEST $CLI volume stop $V0
+TEST $CLI volume delete $V0
+
+cleanup