summaryrefslogtreecommitdiffstats
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
parent10d74166f17fa44c06bd1357e0a4b0b052265425 (diff)
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>
-rw-r--r--api/src/gfapi-messages.h4
-rw-r--r--api/src/gfapi.aliases1
-rw-r--r--api/src/gfapi.map2
-rw-r--r--api/src/glfs-fops.c128
-rw-r--r--api/src/glfs.h44
-rw-r--r--libglusterfs/src/glusterfs.h5
-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
-rw-r--r--xlators/features/locks/src/posix.c2
10 files changed, 694 insertions, 36 deletions
diff --git a/api/src/gfapi-messages.h b/api/src/gfapi-messages.h
index 3eedfa7d071..f231ce99a47 100644
--- a/api/src/gfapi-messages.h
+++ b/api/src/gfapi-messages.h
@@ -73,7 +73,9 @@ GLFS_MSGID(API,
API_MSG_CREATE_HANDLE_FAILED,
API_MSG_INODE_LINK_FAILED,
API_MSG_STATEDUMP_FAILED,
- API_MSG_XREADDIRP_R_FAILED
+ API_MSG_XREADDIRP_R_FAILED,
+ API_MSG_LOCK_INSERT_MERGE_FAILED,
+ API_MSG_SETTING_LOCK_TYPE_FAILED
);
#endif /* !_GFAPI_MESSAGES_H__ */
diff --git a/api/src/gfapi.aliases b/api/src/gfapi.aliases
index 41a01f842fd..88d361dc329 100644
--- a/api/src/gfapi.aliases
+++ b/api/src/gfapi.aliases
@@ -169,3 +169,4 @@ _pub_glfs_upcall_register _glfs_upcall_register$GFAPI_3.13.0
_pub_glfs_upcall_unregister _glfs_upcall_unregister$GFAPI_3.13.0
_pub_glfs_setfsleaseid _glfs_setfsleaseid$GFAPI_4.0.0
+_pub_glfs_file_lock _glfs_file_lock$GFAPI_4.0.0
diff --git a/api/src/gfapi.map b/api/src/gfapi.map
index aa30286c01b..fc47a3b8f42 100644
--- a/api/src/gfapi.map
+++ b/api/src/gfapi.map
@@ -222,5 +222,7 @@ GFAPI_3.13.0 {
} GFAPI_PRIVATE_3.12.0;
GFAPI_4.0.0 {
+ global:
glfs_setfsleaseid;
+ glfs_file_lock;
} GFAPI_3.13.0;
diff --git a/api/src/glfs-fops.c b/api/src/glfs-fops.c
index 287326c4e4a..833ff336634 100644
--- a/api/src/glfs-fops.c
+++ b/api/src/glfs-fops.c
@@ -4250,36 +4250,46 @@ gf_flock_from_flock (struct gf_flock *gf_flock, struct flock *flock)
gf_flock->l_pid = flock->l_pid;
}
-
-int
-pub_glfs_posix_lock (struct glfs_fd *glfd, int cmd, struct flock *flock)
+static int
+glfs_lock_common (struct glfs_fd *glfd, int cmd, struct flock *flock,
+ dict_t *xdata)
{
- int ret = -1;
- xlator_t *subvol = NULL;
- struct gf_flock gf_flock = {0, };
- struct gf_flock saved_flock = {0, };
- fd_t *fd = NULL;
+ int ret = -1;
+ xlator_t *subvol = NULL;
+ struct gf_flock gf_flock = {0, };
+ struct gf_flock saved_flock = {0, };
+ fd_t *fd = NULL;
DECLARE_OLD_THIS;
- __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
+ __GLFS_ENTRY_VALIDATE_FD (glfd, invalid_fs);
+
+ if (!flock) {
+ errno = EINVAL;
+ goto out;
+ }
GF_REF_GET (glfd);
- subvol = glfs_active_subvol (glfd->fs);
- if (!subvol) {
- ret = -1;
- errno = EIO;
- goto out;
- }
+ subvol = glfs_active_subvol (glfd->fs);
+ if (!subvol) {
+ ret = -1;
+ errno = EIO;
+ goto out;
+ }
- fd = glfs_resolve_fd (glfd->fs, subvol, glfd);
- if (!fd) {
- ret = -1;
- errno = EBADFD;
- goto out;
- }
+ fd = glfs_resolve_fd (glfd->fs, subvol, glfd);
+ if (!fd) {
+ ret = -1;
+ errno = EBADFD;
+ goto out;
+ }
+
+ /* Generate glusterfs flock structure from client flock
+ * structure to be processed by server */
+ gf_flock_from_flock (&gf_flock, flock);
- gf_flock_from_flock (&gf_flock, flock);
- gf_flock_from_flock (&saved_flock, flock);
+ /* Keep another copy of flock for split/merge of locks
+ * at client side */
+ gf_flock_from_flock (&saved_flock, flock);
if (glfd->lk_owner.len != 0) {
ret = syncopctx_setfslkowner (&glfd->lk_owner);
@@ -4288,24 +4298,80 @@ pub_glfs_posix_lock (struct glfs_fd *glfd, int cmd, struct flock *flock)
goto out;
}
- ret = syncop_lk (subvol, fd, cmd, &gf_flock, NULL, NULL);
+ ret = syncop_lk (subvol, fd, cmd, &gf_flock, xdata, NULL);
DECODE_SYNCOP_ERR (ret);
- gf_flock_to_flock (&gf_flock, flock);
- if (ret == 0 && (cmd == F_SETLK || cmd == F_SETLKW))
- fd_lk_insert_and_merge (fd, cmd, &saved_flock);
+ /* Convert back from gf_flock to flock as expected by application */
+ gf_flock_to_flock (&gf_flock, flock);
+
+ if (ret == 0 && (cmd == F_SETLK || cmd == F_SETLKW)) {
+ ret = fd_lk_insert_and_merge (fd, cmd, &saved_flock);
+ if (ret) {
+ gf_msg (THIS->name, GF_LOG_ERROR, 0,
+ API_MSG_LOCK_INSERT_MERGE_FAILED,
+ "Lock insertion and splitting/merging failed "
+ "on gfid %s", uuid_utoa (fd->inode->gfid));
+ ret = 0;
+ }
+ }
+
out:
- if (fd)
- fd_unref (fd);
+ if (fd)
+ fd_unref (fd);
if (glfd)
GF_REF_PUT (glfd);
- glfs_subvol_done (glfd->fs, subvol);
+ glfs_subvol_done (glfd->fs, subvol);
__GLFS_EXIT_FS;
invalid_fs:
- return ret;
+ return ret;
+}
+
+int
+pub_glfs_file_lock (struct glfs_fd *glfd, int cmd, struct flock *flock,
+ enum glfs_lock_mode_t lk_mode)
+{
+ int ret = -1;
+ dict_t *xdata_in = NULL;
+
+ if (lk_mode == GLFS_LK_MANDATORY) {
+ /* Create a new dictionary */
+ xdata_in = dict_new ();
+ if (xdata_in == NULL) {
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+
+ /* Set GF_LK_MANDATORY internally within dictionary to map
+ * GLFS_LK_MANDATORY */
+ ret = dict_set_uint32 (xdata_in, GF_LOCK_MODE, GF_LK_MANDATORY);
+ if (ret) {
+ gf_msg (THIS->name, GF_LOG_ERROR, 0,
+ API_MSG_SETTING_LOCK_TYPE_FAILED,
+ "Setting lock type failed");
+ ret = -1;
+ errno = ENOMEM;
+ goto out;
+ }
+ }
+
+ ret = glfs_lock_common (glfd, cmd, flock, xdata_in);
+out:
+ if (xdata_in)
+ dict_unref (xdata_in);
+
+ return ret;
+}
+
+GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_file_lock, 4.0.0);
+
+int
+pub_glfs_posix_lock (struct glfs_fd *glfd, int cmd, struct flock *flock)
+{
+ return glfs_lock_common (glfd, cmd, flock, NULL);
}
GFAPI_SYMVER_PUBLIC_DEFAULT(glfs_posix_lock, 3.4.0);
diff --git a/api/src/glfs.h b/api/src/glfs.h
index 42cbfe7ab6c..5ffed1e0853 100644
--- a/api/src/glfs.h
+++ b/api/src/glfs.h
@@ -774,6 +774,50 @@ char *glfs_realpath (glfs_t *fs, const char *path, char *resolved_path) __THROW
int glfs_posix_lock (glfs_fd_t *fd, int cmd, struct flock *flock) __THROW
GFAPI_PUBLIC(glfs_posix_lock, 3.4.0);
+/*
+ SYNOPSIS
+
+ glfs_file_lock: Request extended byte range lock on a file
+
+ DESCRIPTION
+
+ This function is capable of requesting either advisory or mandatory type
+ byte range locks on a file.
+
+ Note: To set a unique owner key for locks based on a particular file
+ descriptor, make use of glfs_fd_set_lkowner() api to do so before
+ requesting lock via this api. This owner key will be further consumed
+ by other incoming data modifying file operations via the same file
+ descriptor.
+
+ PARAMETERS
+
+ @fd: File descriptor
+
+ @cmd: As specified in man fcntl(2).
+
+ @flock: As specified in man fcntl(2).
+
+ @lk_mode: Required lock type from options available with the
+ enum glfs_lock_mode_t defined below.
+
+ RETURN VALUES
+
+ 0 : Success. Lock has been granted.
+ -1 : Failure. @errno will be set indicating the type of failure.
+
+ */
+
+/* Lock modes used by glfs_file_lock() */
+enum glfs_lock_mode_t {
+ GLFS_LK_ADVISORY = 0,
+ GLFS_LK_MANDATORY
+};
+
+int glfs_file_lock (glfs_fd_t *fd, int cmd, struct flock *flock,
+ enum glfs_lock_mode_t lk_mode) __THROW
+ GFAPI_PUBLIC(glfs_file_lock, 3.13.0);
+
glfs_fd_t *glfs_dup (glfs_fd_t *fd) __THROW
GFAPI_PUBLIC(glfs_dup, 3.4.0);
diff --git a/libglusterfs/src/glusterfs.h b/libglusterfs/src/glusterfs.h
index db4a5ec4029..56be7487ce7 100644
--- a/libglusterfs/src/glusterfs.h
+++ b/libglusterfs/src/glusterfs.h
@@ -301,8 +301,9 @@
#define GF_BACKTRACE_LEN 4096
#define GF_BACKTRACE_FRAME_COUNT 7
-#define GF_LK_ADVISORY 0
-#define GF_LK_MANDATORY 1
+#define GF_LK_ADVISORY 0 /* maps to GLFS_LK_ADVISORY from libgfapi*/
+#define GF_LK_MANDATORY 1 /* maps to GLFS_LK_MANDATORY from libgfapi*/
+#define GF_LOCK_MODE "glusterfs.lk.lkmode"
const char *fop_enum_to_pri_string (glusterfs_fop_t fop);
diff --git a/tests/basic/gfapi/Makefile b/tests/basic/gfapi/Makefile
index e30fefea5b9..1c5cf03ca3d 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 00000000000..6c62f437a0f
--- /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 00000000000..27062e1f6c2
--- /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
diff --git a/xlators/features/locks/src/posix.c b/xlators/features/locks/src/posix.c
index 440b272b21e..1e1d9e5ae30 100644
--- a/xlators/features/locks/src/posix.c
+++ b/xlators/features/locks/src/posix.c
@@ -2239,7 +2239,7 @@ pl_lk (call_frame_t *frame, xlator_t *this,
priv = this->private;
- ret = dict_get_uint32 (xdata, "lkmode", &lk_flags);
+ ret = dict_get_uint32 (xdata, GF_LOCK_MODE, &lk_flags);
if (ret == 0) {
if (priv->mandatory_mode == MLK_NONE)
gf_log (this->name, GF_LOG_DEBUG, "Lock flags received "