diff --git a/lustre/include/obd_support.h b/lustre/include/obd_support.h
index 62207d137ee59829fa5faecbbea8f0047d6634ae..84c0790545aadd33efddf231a06d7a1bb89277e4 100644
--- a/lustre/include/obd_support.h
+++ b/lustre/include/obd_support.h
@@ -229,6 +229,7 @@ extern unsigned int obd_alloc_fail_rate;
 #define OBD_FAIL_LDLM_PAUSE_CANCEL       0x312
 #define OBD_FAIL_LDLM_CLOSE_THREAD       0x313
 #define OBD_FAIL_LDLM_CANCEL_BL_CB_RACE  0x314
+#define OBD_FAIL_LDLM_CP_CB_WAIT         0x315
 
 #define OBD_FAIL_OSC                     0x400
 #define OBD_FAIL_OSC_BRW_READ_BULK       0x401
diff --git a/lustre/ldlm/ldlm_flock.c b/lustre/ldlm/ldlm_flock.c
index f5eb0b94221d69e20fbfc1b578c5535a7bf80ef0..b158d1d448997766f3ac280940793580f75e1d2d 100644
--- a/lustre/ldlm/ldlm_flock.c
+++ b/lustre/ldlm/ldlm_flock.c
@@ -558,6 +558,7 @@ ldlm_flock_completion_ast(struct ldlm_lock *lock, int flags, void *data)
         RETURN(rc);
  
 granted:
+        OBD_FAIL_TIMEOUT(OBD_FAIL_LDLM_CP_CB_WAIT, 10);
         LDLM_DEBUG(lock, "client-side enqueue granted");
         ns = lock->l_resource->lr_namespace;
         lock_res_and_lock(lock);
diff --git a/lustre/tests/Makefile.am b/lustre/tests/Makefile.am
index 93712fa549a09d771016bc19de17fe70261de44c..65b0f4a6ad851e68bc56636d44f7a210b0f15009 100644
--- a/lustre/tests/Makefile.am
+++ b/lustre/tests/Makefile.am
@@ -59,6 +59,9 @@ multiop_LDADD=$(LIBLUSTREAPI)
 ll_dirstripe_verify_SOURCES= ll_dirstripe_verify.c
 ll_dirstripe_verify_LDADD= -L$(top_builddir)/lustre/utils -llustreapi
 
+flocks_test_SOURCES=flocks_test.c
+flocks_test_LDADD=-lpthread
+
 if MPITESTS
 #LAM_LD_FLAGS=-L/opt/lam/lib -lmpi -llam -lpthread
 LAM_LD_FLAGS=-lmpich -lpthread
diff --git a/lustre/tests/flocks_test.c b/lustre/tests/flocks_test.c
index 633e1b1b9a4c1cbcc42c9f8cf800305f47f0ce6e..97890d85f57976935eba4bad1722c14bca77616c 100644
--- a/lustre/tests/flocks_test.c
+++ b/lustre/tests/flocks_test.c
@@ -40,38 +40,118 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-
+#include <pthread.h>
 #include <sys/file.h>
+#include <stdarg.h>
 
-void usage(void)
+#define MAX_PATH_LENGTH 4096
+/**
+ * helper functions
+ */
+int t_fcntl(int fd, int cmd, ...)
+{
+        va_list ap;
+        long arg;
+        struct flock *lock;
+        int rc = -1;
+
+        va_start(ap, cmd);
+        switch (cmd) {
+        case F_GETFL:
+                va_end(ap);
+                rc = fcntl(fd, cmd);
+                if (rc == -1) {
+                        fprintf(stderr, "fcntl GETFL failed: %s\n",
+                                strerror(errno));
+                        return(1);
+                }
+                break;
+        case F_SETFL:
+                arg = va_arg(ap, long);
+                va_end(ap);
+                rc = fcntl(fd, cmd, arg);
+                if (rc == -1) {
+                        fprintf(stderr, "fcntl SETFL %ld failed: %s\n",
+                                arg, strerror(errno));
+                        return(1);
+                }
+                break;
+        case F_GETLK:
+        case F_SETLK:
+        case F_SETLKW:
+                lock = va_arg(ap, struct flock *);
+                va_end(ap);
+                rc = fcntl(fd, cmd, lock);
+                if (rc == -1) {
+                        fprintf(stderr, "fcntl cmd %d failed: %s\n",
+                                cmd, strerror(errno));
+                        return(1);
+                }
+                break;
+        case F_DUPFD:
+                arg = va_arg(ap, long);
+                va_end(ap);
+                rc = fcntl(fd, cmd, arg);
+                if (rc == -1) {
+                        fprintf(stderr, "fcntl F_DUPFD %d failed: %s\n",
+                                (int)arg, strerror(errno));
+                        return(1);
+                }
+                break;
+        default:
+                va_end(ap);
+                fprintf(stderr, "fcntl cmd %d not supported\n", cmd);
+                return(1);
+        }
+        return rc;
+}
+
+int t_unlink(const char *path)
 {
-        fprintf(stderr, "usage: ./flocks_test on|off -c|-f|-l /path/to/file\n");
-        exit(EXIT_FAILURE);
+        int rc;
+
+        rc = unlink(path);
+        if (rc)
+                fprintf(stderr, "unlink(%s) error: %s\n", path, strerror(errno));
+        return rc;
 }
 
-int main(int argc, char *argv[])
+/** =================================================================
+ * test number 1
+ * 
+ * normal flock test
+ */
+void t1_usage(void)
+{
+        fprintf(stderr, "usage: ./flocks_test 1 on|off -c|-f|-l /path/to/file\n");
+}
+
+int t1(int argc, char *argv[])
 {
         int fd;
         int mount_with_flock = 0;
         int error = 0;
 
-        if (argc != 4)
-                usage();
-        
-        if (!strncmp(argv[1], "on", 3)) {
+        if (argc != 5) {
+                t1_usage();
+                return EXIT_FAILURE;
+        }
+
+        if (!strncmp(argv[2], "on", 3)) {
                 mount_with_flock = 1;
-        } else if (!strncmp(argv[1], "off", 4)) {
+        } else if (!strncmp(argv[2], "off", 4)) {
                 mount_with_flock = 0;
         } else {
-                usage();
+                t1_usage();
+                return EXIT_FAILURE;
         }
 
-        if ((fd = open(argv[3], O_RDWR)) < 0) {
-                fprintf(stderr, "Couldn't open file: %s\n", argv[2]);
-                exit(EXIT_FAILURE);
+        if ((fd = open(argv[4], O_RDWR)) < 0) {
+                fprintf(stderr, "Couldn't open file: %s\n", argv[3]);
+                return EXIT_FAILURE;
         }
 
-        if (!strncmp(argv[2], "-c", 3)) {
+        if (!strncmp(argv[3], "-c", 3)) {
                 struct flock fl;
 
                 fl.l_type = F_RDLCK;
@@ -80,12 +160,13 @@ int main(int argc, char *argv[])
                 fl.l_len = 1;
 
                 error = fcntl(fd, F_SETLK, &fl);
-        } else if (!strncmp(argv[2], "-l", 3)) {
+        } else if (!strncmp(argv[3], "-l", 3)) {
                 error = lockf(fd, F_LOCK, 1);
-        } else if (!strncmp(argv[2], "-f", 3)) {
+        } else if (!strncmp(argv[3], "-f", 3)) {
                 error = flock(fd, LOCK_EX);
         } else {
-                usage();
+                t1_usage();
+                return EXIT_FAILURE;
         }
 
         if (mount_with_flock)
@@ -93,3 +174,128 @@ int main(int argc, char *argv[])
         else
                 return((error == 0) ? EXIT_FAILURE : EXIT_SUCCESS);
 }
+
+/** ===============================================================
+ * test number 2
+ * 
+ * 2 threads flock ops interweave
+ */
+typedef struct {
+        struct flock* lock;
+        int fd;
+} th_data;
+
+void* t2_thread1(void *arg)
+{
+        struct flock *lock = ((th_data *)arg)->lock;
+        int fd             = ((th_data *)arg)->fd;
+
+        printf("thread 1: set write lock (blocking)\n");
+        lock->l_type = F_WRLCK;
+        t_fcntl(fd, F_SETLKW, lock);
+        printf("thread 1: set write lock done\n");
+        t_fcntl(fd, F_GETLK, lock);
+        printf("thread 1: unlock\n");
+        lock->l_type = F_UNLCK;
+        t_fcntl(fd, F_SETLK, lock);
+        printf("thread 1: unlock done\n");
+        return 0;
+}
+
+void* t2_thread2(void *arg)
+{
+        struct flock *lock = ((th_data *)arg)->lock;
+        int fd             = ((th_data *)arg)->fd;
+
+        sleep(2);
+        printf("thread 2: unlock\n");
+        lock->l_type = F_UNLCK;
+        t_fcntl(fd, F_SETLK, lock);
+        printf("thread 2: unlock done\n");
+        printf("thread 2: set write lock (non-blocking)\n");
+        lock->l_type = F_WRLCK;
+        t_fcntl(fd, F_SETLK, lock);
+        printf("thread 2: set write lock done\n");
+        t_fcntl(fd, F_GETLK, lock);
+        return 0;
+}
+
+int t2(int argc, char* argv[])
+{
+        struct flock lock = {
+                .l_type = F_RDLCK,
+                .l_whence = SEEK_SET,
+        };
+        char file[MAX_PATH_LENGTH] = "";
+        int  fd, rc;
+        pthread_t th1, th2;
+        th_data   ta;
+
+        snprintf(file, MAX_PATH_LENGTH, "%s/test_t2_file", argv[2]);
+
+        fd = open(file, O_RDWR|O_CREAT, (mode_t)0666);
+        if (fd < 0) {
+                fprintf(stderr, "error open file: %s\n", file);
+                return EXIT_FAILURE;
+        }
+
+        t_fcntl(fd, F_SETFL, O_APPEND);
+        if (!(rc = t_fcntl(fd, F_GETFL)) & O_APPEND) {
+                fprintf(stderr, "error get flag: ret %x\n", rc);
+                return EXIT_FAILURE;
+        }
+
+        ta.lock = &lock;
+        ta.fd   = fd;
+        rc = pthread_create(&th1, NULL, t2_thread1, &ta);
+        if (rc) {
+                fprintf(stderr, "error create thread 1\n");
+                rc = EXIT_FAILURE;
+                goto out;
+        }
+        rc = pthread_create(&th2, NULL, t2_thread2, &ta);
+        if (rc) {
+                fprintf(stderr, "error create thread 2\n");
+                rc = EXIT_FAILURE;
+                goto out;
+        }
+        (void)pthread_join(th1, NULL);
+        (void)pthread_join(th2, NULL);
+out:
+        t_unlink(file);
+        close(fd);
+        return rc;
+}
+
+/** ==============================================================
+ * program entry
+ */
+void usage(void)
+{
+        fprintf(stderr, "usage: ./flocks_test test# [corresponding arguments]\n");
+}
+
+int main(int argc, char* argv[])
+{
+        int test_no;
+        int rc = EXIT_SUCCESS;
+
+        if (argc < 1) {
+                usage();
+                exit(EXIT_FAILURE);
+        }
+        test_no = atoi(argv[1]);
+
+        switch(test_no) {
+        case 1:
+                rc = t1(argc, argv);
+                break;
+        case 2:
+                rc = t2(argc, argv);
+                break;
+        default:
+                fprintf(stderr, "unknow test number %s\n", argv[1]);
+                break;
+        }
+        return rc;
+}
diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh
index 40d4b6f3e5bc39156e92f48face716f4177bcd5f..a4c96567c4c5bc0ca801613f4a52979ea683a484 100644
--- a/lustre/tests/sanity.sh
+++ b/lustre/tests/sanity.sh
@@ -4093,9 +4093,9 @@ test_105a() {
         touch $DIR/$tfile
         if [ -n "`mount | grep \"$DIR.*flock\" | grep -v noflock`" ];
         then
-                flocks_test on -f $DIR/$tfile || error "fail flock on"
+                flocks_test 1 on -f $DIR/$tfile || error "fail flock on"
         else
-                flocks_test off -f $DIR/$tfile || error "fail flock off"
+                flocks_test 1 off -f $DIR/$tfile || error "fail flock off"
         fi
 }
 run_test 105a "flock when mounted without -o flock test ========"
@@ -4104,9 +4104,9 @@ test_105b() {
         touch $DIR/$tfile
         if [ -n "`mount | grep \"$DIR.*flock\" | grep -v noflock`" ];
         then
-                flocks_test on -c $DIR/$tfile || error "fail flock on"
+                flocks_test 1 on -c $DIR/$tfile || error "fail flock on"
         else
-                flocks_test off -c $DIR/$tfile || error "fail flock off"
+                flocks_test 1 off -c $DIR/$tfile || error "fail flock off"
         fi
 }
 run_test 105b "fcntl when mounted without -o flock test ========"
@@ -4115,13 +4115,23 @@ test_105c() {
         touch $DIR/$tfile
         if [ -n "`mount | grep \"$DIR.*flock\" | grep -v noflock`" ];
         then
-                flocks_test on -l $DIR/$tfile || error "fail flock on"
+                flocks_test 1 on -l $DIR/$tfile || error "fail flock on"
         else
-                flocks_test off -l $DIR/$tfile || error "fail flock off"
+                flocks_test 1 off -l $DIR/$tfile || error "fail flock off"
         fi
 }
 run_test 105c "lockf when mounted without -o flock test ========"
 
+test_105d() { # bug 15924
+        mkdir -p $DIR/$tdir
+        [ -z "`mount | grep \"$DIR.*flock\" | grep -v noflock`" ] && \
+                skip "mount w/o flock enabled" && return
+        #define OBD_FAIL_LDLM_CP_CB_WAIT  0x315
+        $LCTL set_param fail_loc=0x80000315
+        flocks_test 2 $DIR/$tdir
+}
+run_test 105d "flock race (should not freeze) ========"
+
 test_106() { #bug 10921
 	mkdir -p $DIR/$tdir
 	$DIR/$tdir && error "exec $DIR/$tdir succeeded"