From 8de03ea1200480b922d5ba05b69dc94db60496f5 Mon Sep 17 00:00:00 2001
From: "Hongzhi.Song" <hongzhi.song@windriver.com>
Date: Sat, 15 Sep 2018 22:39:32 -0400
Subject: [PATCH] syscalls/fcntl: make OFD command use fcntl64() syscall on
 32-bit

To cope with glibc commit:
  06ab719d30b0 ("Fix Linux fcntl OFD locks for non-LFS architectures
(BZ#20251)")

WIP: Still need to test this with new glibc.
     Test with old glibc look OK so far.

Signed-off-by: Jan Stancek <jstancek@redhat.com>

Upstream-Status: Backport
    Backported from upstream maillist
    https://lists.linux.it/pipermail/ltp/2018-September/009370.html

Signed-off-by: Hongzhi Song <hongzhi.song@windriver.com>
---
 testcases/kernel/syscalls/fcntl/fcntl34.c      | 12 +++++++---
 testcases/kernel/syscalls/fcntl/fcntl36.c      | 23 +++++++++++++-----
 testcases/kernel/syscalls/fcntl/fcntl_common.h | 32 ++++++++++++++++++++++++++
 3 files changed, 58 insertions(+), 9 deletions(-)
 create mode 100644 testcases/kernel/syscalls/fcntl/fcntl_common.h

diff --git a/testcases/kernel/syscalls/fcntl/fcntl34.c b/testcases/kernel/syscalls/fcntl/fcntl34.c
index aa29cf9..109f834 100644
--- a/testcases/kernel/syscalls/fcntl/fcntl34.c
+++ b/testcases/kernel/syscalls/fcntl/fcntl34.c
@@ -28,6 +28,7 @@
 #include "lapi/fcntl.h"
 #include "tst_safe_pthread.h"
 #include "tst_test.h"
+#include "fcntl_common.h"
 
 static int thread_cnt;
 static const int max_thread_cnt = 32;
@@ -68,7 +69,12 @@ void *thread_fn_01(void *arg)
 
 	memset(buf, (intptr_t)arg, write_size);
 
-	struct flock64 lck = {
+    /* see explanation in fcntl_common.h */
+    #ifdef USE_STRUCT_FLOCK
+        struct flock lck = {
+    #else
+        struct flock64 lck = {
+    #endif
 		.l_whence = SEEK_SET,
 		.l_start  = 0,
 		.l_len    = 1,
@@ -76,13 +82,13 @@ void *thread_fn_01(void *arg)
 
 	for (i = 0; i < writes_num; ++i) {
 		lck.l_type = F_WRLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
+        my_fcntl(fd, F_OFD_SETLKW, &lck);
 
 		SAFE_LSEEK(fd, 0, SEEK_END);
 		SAFE_WRITE(1, fd, buf, write_size);
 
 		lck.l_type = F_UNLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
+        my_fcntl(fd, F_OFD_SETLKW, &lck);
 
 		sched_yield();
 	}
diff --git a/testcases/kernel/syscalls/fcntl/fcntl36.c b/testcases/kernel/syscalls/fcntl/fcntl36.c
index 3246d13..f263b6b 100644
--- a/testcases/kernel/syscalls/fcntl/fcntl36.c
+++ b/testcases/kernel/syscalls/fcntl/fcntl36.c
@@ -57,6 +57,7 @@
 #include "lapi/fcntl.h"
 #include "tst_safe_pthread.h"
 #include "tst_test.h"
+#include "fcntl_common.h"
 
 static int thread_cnt;
 static int fail_flag = 0;
@@ -87,7 +88,12 @@ static void *fn_ofd_w(void *arg)
 	int fd = SAFE_OPEN(fname, O_RDWR);
 	long wt = pa->cnt;
 
-	struct flock64 lck = {
+    /* see explanation in fcntl_common.h */
+    #ifdef USE_STRUCT_FLOCK
+        struct flock lck = {
+    #else
+        struct flock64 lck = {
+    #endif
 		.l_whence = SEEK_SET,
 		.l_start  = pa->offset,
 		.l_len    = pa->length,
@@ -99,13 +105,13 @@ static void *fn_ofd_w(void *arg)
 		memset(buf, wt, pa->length);
 
 		lck.l_type = F_WRLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
+        my_fcntl(fd, F_OFD_SETLKW, &lck);
 
 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
 		SAFE_WRITE(1, fd, buf, pa->length);
 
 		lck.l_type = F_UNLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
+        my_fcntl(fd, F_OFD_SETLKW, &lck);
 
 		wt++;
 		if (wt >= 255)
@@ -166,7 +172,12 @@ static void *fn_ofd_r(void *arg)
 	int i;
 	int fd = SAFE_OPEN(fname, O_RDWR);
 
-	struct flock64 lck = {
+    /* see explanation in fcntl_common.h */
+    #ifdef USE_STRUCT_FLOCK
+        struct flock lck = {
+    #else
+        struct flock64 lck = {
+    #endif
 		.l_whence = SEEK_SET,
 		.l_start  = pa->offset,
 		.l_len    = pa->length,
@@ -178,7 +189,7 @@ static void *fn_ofd_r(void *arg)
 		memset(buf, 0, pa->length);
 
 		lck.l_type = F_RDLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLKW, &lck);
+        my_fcntl(fd, F_OFD_SETLKW, &lck);
 
 		/* rlock acquired */
 		SAFE_LSEEK(fd, pa->offset, SEEK_SET);
@@ -209,7 +220,7 @@ static void *fn_ofd_r(void *arg)
 		}
 
 		lck.l_type = F_UNLCK;
-		SAFE_FCNTL(fd, F_OFD_SETLK, &lck);
+        my_fcntl(fd, F_OFD_SETLK, &lck);
 
 		sched_yield();
 	}
diff --git a/testcases/kernel/syscalls/fcntl/fcntl_common.h b/testcases/kernel/syscalls/fcntl/fcntl_common.h
new file mode 100644
index 0000000..3fe399b
--- /dev/null
+++ b/testcases/kernel/syscalls/fcntl/fcntl_common.h
@@ -0,0 +1,32 @@
+#include "lapi/syscalls.h"
+
+/*
+ * glibc commit:
+ *   06ab719d30b0 ("Fix Linux fcntl OFD locks for non-LFS architectures (BZ#20251)")
+ * changed behavior of arg parameter for OFD commands. It is no
+ * longer passing arg directly to syscall, but expects it to be
+ * 'struct flock'.
+ *
+ * On 64-bit or _FILE_OFFSET_BITS == 64 we can use fcntl() and
+ * struct flock with any glibc version. struct flock and flock64
+ * should be identical.
+ *
+ * On 32-bit, older glibc would pass arg directly, recent one treats
+ * it as 'struct flock' and converts it to 'struct flock64'.
+ * So, for 32-bit we use fcntl64 syscall directly with struct flock64.
+ */
+#if __WORDSIZE == 64 || _FILE_OFFSET_BITS == 64
+#define USE_STRUCT_FLOCK
+static int my_fcntl(int fd, int cmd, void *lck)
+{
+        return SAFE_FCNTL(fd, cmd, lck);
+}
+#else
+static int my_fcntl(int fd, int cmd, void *lck)
+{
+        int ret = tst_syscall(__NR_fcntl64, fd, cmd, lck);
+        if (ret == -1)
+                tst_brk(TBROK|TERRNO, "fcntl64");
+        return ret;
+}
+#endif
-- 
2.8.1

