+// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2000-2003 Silicon Graphics, Inc.
+ * Copyright (c) 2019 Intel Corp.
* All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it would be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
- * Synchronized byte range lock exerciser
+ * Synchronized byte range lock and lease exerciser
*/
#include <stdio.h>
#include <byteswap.h>
#include <errno.h>
#include <string.h>
+#include <signal.h>
+
#define HEX_2_ASC(x) ((x) > 9) ? (x)-10+'a' : (x)+'0'
#define FILE_SIZE 1024
#define PLATFORM_INIT() /*no-op*/
#define HANDLE int
#define INVALID_HANDLE -1
-#define OPEN(N,F) (open(N, F|O_CREAT|O_RDWR|O_BINARY| \
- (D_flag ? O_DIRECT : 0), 0644))
#define SEEK(H, O) (lseek(H, O, SEEK_SET))
#define READ(H, B, L) (read(H, B, L))
#define WRITE(H, B, L) (write(H, B, L))
#define RAND() (rand())
#define SRAND(s) (srand(s))
-#define SLEEP(s) (sleep(s))
#define MIN(A,B) (((A)<(B))?(A):(B))
#define MAX(A,B) (((A)>(B))?(A):(B))
static char *filename = 0;
static int debug = 0;
static int server = 1;
-static int maxio = 8192;
-static int port = 7890;
-static int reopen=0;
-static int closed=0;
+static int port = 0;
static int testnumber = -1;
static int saved_errno = 0;
+static int got_sigio = 0;
static SOCKET s_fd = -1; /* listen socket */
static SOCKET c_fd = -1; /* IPC socket */
static HANDLE f_fd = INVALID_HANDLE; /* shared file */
-static char *buf; /* I/O buffer */
-static int D_flag = 0;
-#define WRLOCK 0
-#define RDLOCK 1
-#define UNLOCK 2
-#define F_CLOSE 3
-#define F_OPEN 4
+#define CMD_WRLOCK 0
+#define CMD_RDLOCK 1
+#define CMD_UNLOCK 2
+#define CMD_CLOSE 3
+#define CMD_OPEN 4
+#define CMD_WRTEST 5
+#define CMD_RDTEST 6
+#define CMD_SETLEASE 7
+#define CMD_GETLEASE 8
+#define CMD_SIGIO 9
+#define CMD_WAIT_SIGIO 10
#define PASS 1
#define FAIL 0
#define RESULT 4
#define WHO 5
#define FLAGS 2 /* index 2 is also used for do_open() flag, see below */
+#define ARG FLAGS /* Arguments for Lease operations */
+#define TIME FLAGS /* Time for waiting on sigio */
+static char *get_cmd_str(int cmd)
+{
+ switch (cmd) {
+ case CMD_WRLOCK: return "write lock"; break;
+ case CMD_RDLOCK: return "read lock"; break;
+ case CMD_UNLOCK: return "unlock"; break;
+ case CMD_CLOSE: return "close"; break;
+ case CMD_OPEN: return "open"; break;
+ case CMD_WRTEST: return "Wait for SIGIO"; break;
+ case CMD_RDTEST: return "Truncate"; break;
+ case CMD_SETLEASE: return "Set Lease"; break;
+ case CMD_GETLEASE: return "Get Lease"; break;
+ case CMD_SIGIO: return "Setup SIGIO"; break;
+ case CMD_WAIT_SIGIO: return "Wait for SIGIO"; break;
+ }
+ return "unknown";
+}
/*
* flags for Mac OS X do_open()
* O_RDONLY 0x0000
* (or vice versa)
*/
-char *descriptions[] = {
+char *lock_descriptions[] = {
/* 1 */"Add a lock to an empty lock list",
/* 2 */"Add a lock to the start and end of a list - no overlaps",
/* 3 */"Add a lock to the middle of a list - no overlap",
/* 26 */"Acquire read and write locks with overlapping ranges",
/* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
/* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
+ /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
#if defined(macosx)
- /* 29 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
- /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
- /* 31 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
+ /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
+ /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
+ /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
#endif
};
-static int64_t tests[][6] =
- /* test # Action offset length expected server/client */
+static int64_t lock_tests[][6] =
+ /* test # Action [offset|flags] length expected server/client */
{
/* Various simple tests exercising the list */
-/* SECTION 1: WRITE and UNLOCK with the same process (SERVER) */
+/* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
/* Add a lock to an empty list */
- {1, WRLOCK, 1, 10, PASS, SERVER },
- {1, UNLOCK, 1, 10, PASS, SERVER },
+ {1, CMD_WRLOCK, 1, 10, PASS, SERVER },
+ {1, CMD_UNLOCK, 1, 10, PASS, SERVER },
/* Add a lock to the start and end of a list - 1, 13 - no overlap */
- {2, WRLOCK, 10, 10, PASS, SERVER },
- {2, WRLOCK, 30, 10, PASS, SERVER },
- {2, WRLOCK, 50, 10, PASS, SERVER },
- {2, WRLOCK, 1, 5, PASS, SERVER },
- {2, WRLOCK, 70, 5, PASS, SERVER },
+ {2, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {2, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {2, CMD_WRLOCK, 50, 10, PASS, SERVER },
+ {2, CMD_WRLOCK, 1, 5, PASS, SERVER },
+ {2, CMD_WRLOCK, 70, 5, PASS, SERVER },
- {2, UNLOCK, 10, 10, PASS, SERVER },
- {2, UNLOCK, 30, 10, PASS, SERVER },
- {2, UNLOCK, 50, 10, PASS, SERVER },
- {2, UNLOCK, 1, 5, PASS, SERVER },
- {2, UNLOCK, 70, 5, PASS, SERVER },
+ {2, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {2, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {2, CMD_UNLOCK, 50, 10, PASS, SERVER },
+ {2, CMD_UNLOCK, 1, 5, PASS, SERVER },
+ {2, CMD_UNLOCK, 70, 5, PASS, SERVER },
/* Add a lock to the middle of a list - no overlap */
- {3, WRLOCK, 10, 10, PASS, SERVER },
- {3, WRLOCK, 30, 10, PASS, SERVER },
- {3, WRLOCK, 50, 10, PASS, SERVER },
- {3, WRLOCK, 42, 5, PASS, SERVER },
+ {3, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {3, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {3, CMD_WRLOCK, 50, 10, PASS, SERVER },
+ {3, CMD_WRLOCK, 42, 5, PASS, SERVER },
- {3, UNLOCK, 10, 10, PASS, SERVER },
- {3, UNLOCK, 30, 10, PASS, SERVER },
- {3, UNLOCK, 50, 10, PASS, SERVER },
- {3, UNLOCK, 42, 5, PASS, SERVER },
+ {3, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {3, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {3, CMD_UNLOCK, 50, 10, PASS, SERVER },
+ {3, CMD_UNLOCK, 42, 5, PASS, SERVER },
/* Add different lock types to middle of the list - overlap exact match - 3 */
- {4, WRLOCK, 10, 10, PASS, SERVER },
- {4, WRLOCK, 30, 10, PASS, SERVER },
- {4, WRLOCK, 50, 10, PASS, SERVER },
+ {4, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Exact match - same lock type */
- {4, WRLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
/* Exact match - different lock type */
- {4, RDLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_RDLOCK, 30, 10, PASS, SERVER },
/* Exact match - unlock */
- {4, UNLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
/* New lock - as above, inserting in the list again */
- {4, WRLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
- {4, UNLOCK, 10, 10, PASS, SERVER },
- {4, UNLOCK, 30, 10, PASS, SERVER },
- {4, UNLOCK, 50, 10, PASS, SERVER },
+ {4, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {4, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
- {5, WRLOCK, 10, 10, PASS, SERVER },
- {5, WRLOCK, 30, 10, PASS, SERVER },
- {5, WRLOCK, 50, 10, PASS, SERVER },
+ {5, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {5, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {5, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end overlaps */
- {5, WRLOCK, 30, 15, PASS, SERVER },
+ {5, CMD_WRLOCK, 30, 15, PASS, SERVER },
/* The start is before, end is the same */
- {5, WRLOCK, 25, 20, PASS, SERVER },
+ {5, CMD_WRLOCK, 25, 20, PASS, SERVER },
/* Both start and end overlap */
- {5, WRLOCK, 22, 26, PASS, SERVER },
+ {5, CMD_WRLOCK, 22, 26, PASS, SERVER },
- {5, UNLOCK, 10, 10, PASS, SERVER },
- {5, UNLOCK, 22, 26, PASS, SERVER },
- {5, UNLOCK, 50, 10, PASS, SERVER },
+ {5, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {5, CMD_UNLOCK, 22, 26, PASS, SERVER },
+ {5, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
- {6, WRLOCK, 10, 10, PASS, SERVER },
- {6, WRLOCK, 30, 10, PASS, SERVER },
- {6, WRLOCK, 50, 10, PASS, SERVER },
+ {6, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {6, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {6, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end is in the middle of old lock - NOP */
- {6, WRLOCK, 30, 5, PASS, SERVER },
+ {6, CMD_WRLOCK, 30, 5, PASS, SERVER },
/* The start and end are in the middle of old lock - NOP */
- {6, WRLOCK, 32, 6, PASS, SERVER },
+ {6, CMD_WRLOCK, 32, 6, PASS, SERVER },
/* Start in the middle and end is the same - NOP */
- {6, WRLOCK, 32, 8, PASS, SERVER },
+ {6, CMD_WRLOCK, 32, 8, PASS, SERVER },
- {6, UNLOCK, 10, 10, PASS, SERVER },
- {6, UNLOCK, 30, 10, PASS, SERVER },
- {6, UNLOCK, 32, 8, PASS, SERVER },
- {6, UNLOCK, 50, 10, PASS, SERVER },
+ {6, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {6, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {6, CMD_UNLOCK, 32, 8, PASS, SERVER },
+ {6, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock which starts before any old lock in the list - 2,9 */
- {7, WRLOCK, 10, 10, PASS, SERVER },
- {7, WRLOCK, 30, 10, PASS, SERVER },
- {7, WRLOCK, 50, 10, PASS, SERVER },
+ {7, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {7, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {7, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Here is the new lock */
- {7, WRLOCK, 27, 10, PASS, SERVER },
+ {7, CMD_WRLOCK, 27, 10, PASS, SERVER },
/* Go again with the end of the new lock matching the start of old lock */
- {7, WRLOCK, 25, 2, PASS, SERVER },
+ {7, CMD_WRLOCK, 25, 2, PASS, SERVER },
- {7, UNLOCK, 10, 10, PASS, SERVER },
- {7, UNLOCK, 25, 15, PASS, SERVER },
- {7, UNLOCK, 50, 10, PASS, SERVER },
+ {7, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {7, CMD_UNLOCK, 25, 15, PASS, SERVER },
+ {7, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
- {8, WRLOCK, 10, 10, PASS, SERVER },
- {8, WRLOCK, 30, 10, PASS, SERVER },
- {8, WRLOCK, 50, 10, PASS, SERVER },
+ {8, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {8, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {8, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Here is the new lock */
- {8, WRLOCK, 35, 10, PASS, SERVER },
+ {8, CMD_WRLOCK, 35, 10, PASS, SERVER },
/* Go again with the end of the new lock matching the start of old lock */
- {8, WRLOCK, 45, 2, PASS, SERVER },
+ {8, CMD_WRLOCK, 45, 2, PASS, SERVER },
- {8, UNLOCK, 10, 10, PASS, SERVER },
- {8, UNLOCK, 30, 17, PASS, SERVER },
- {8, UNLOCK, 50, 10, PASS, SERVER },
-/* SECTION 2: Overlapping READ and WRITE and UNLOCK with the same process (SERVER) */
+ {8, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {8, CMD_UNLOCK, 30, 17, PASS, SERVER },
+ {8, CMD_UNLOCK, 50, 10, PASS, SERVER },
+/* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
/* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
- {9, WRLOCK, 10, 10, PASS, SERVER },
- {9, WRLOCK, 30, 10, PASS, SERVER },
- {9, WRLOCK, 50, 10, PASS, SERVER },
+ {9, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {9, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {9, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end overlaps */
- {9, RDLOCK, 30, 15, PASS, SERVER },
+ {9, CMD_RDLOCK, 30, 15, PASS, SERVER },
/* The start is before, end is the same */
- {9, WRLOCK, 25, 20, PASS, SERVER },
+ {9, CMD_WRLOCK, 25, 20, PASS, SERVER },
/* Both start and end overlap */
- {9, RDLOCK, 22, 26, PASS, SERVER },
+ {9, CMD_RDLOCK, 22, 26, PASS, SERVER },
- {9, UNLOCK, 10, 10, PASS, SERVER },
- {9, UNLOCK, 22, 26, PASS, SERVER },
- {9, UNLOCK, 50, 10, PASS, SERVER },
+ {9, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {9, CMD_UNLOCK, 22, 26, PASS, SERVER },
+ {9, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
- {10, WRLOCK, 10, 10, PASS, SERVER },
- {10, WRLOCK, 30, 10, PASS, SERVER },
- {10, WRLOCK, 50, 10, PASS, SERVER },
+ {10, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {10, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {10, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end is in the middle of old lock */
- {10, RDLOCK, 30, 5, PASS, SERVER },
+ {10, CMD_RDLOCK, 30, 5, PASS, SERVER },
/* The start and end are in the middle of a lock */
- {10, WRLOCK, 32, 2, PASS, SERVER },
+ {10, CMD_WRLOCK, 32, 2, PASS, SERVER },
/* Start in the middle and end is the same */
- {10, RDLOCK, 36, 5, PASS, SERVER },
+ {10, CMD_RDLOCK, 36, 5, PASS, SERVER },
- {10, UNLOCK, 10, 10, PASS, SERVER },
- {10, UNLOCK, 30, 11, PASS, SERVER },
- {10, UNLOCK, 50, 10, PASS, SERVER },
+ {10, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {10, CMD_UNLOCK, 30, 11, PASS, SERVER },
+ {10, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add different new lock types which start before the old lock in the list - 2,9 */
- {11, WRLOCK, 10, 10, PASS, SERVER },
- {11, WRLOCK, 30, 10, PASS, SERVER },
- {11, WRLOCK, 50, 10, PASS, SERVER },
+ {11, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {11, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {11, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Here is the new lock */
- {11, RDLOCK, 27, 10, PASS, SERVER },
+ {11, CMD_RDLOCK, 27, 10, PASS, SERVER },
/* Go again with the end of the new lock matching the start of lock */
- {11, WRLOCK, 25, 3, PASS, SERVER },
+ {11, CMD_WRLOCK, 25, 3, PASS, SERVER },
- {11, UNLOCK, 10, 10, PASS, SERVER },
- {11, UNLOCK, 25, 15, PASS, SERVER },
- {11, UNLOCK, 50, 10, PASS, SERVER },
+ {11, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {11, CMD_UNLOCK, 25, 15, PASS, SERVER },
+ {11, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
- {12, WRLOCK, 10, 10, PASS, SERVER },
- {12, WRLOCK, 30, 10, PASS, SERVER },
- {12, WRLOCK, 50, 10, PASS, SERVER },
+ {12, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {12, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {12, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Here is the new lock */
- {12, RDLOCK, 35, 10, PASS, SERVER },
+ {12, CMD_RDLOCK, 35, 10, PASS, SERVER },
/* Go again with the end of the new lock matching the start of old lock */
- {12, WRLOCK, 44, 3, PASS, SERVER },
+ {12, CMD_WRLOCK, 44, 3, PASS, SERVER },
- {12, UNLOCK, 10, 10, PASS, SERVER },
- {12, UNLOCK, 30, 18, PASS, SERVER },
- {12, UNLOCK, 50, 10, PASS, SERVER },
+ {12, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {12, CMD_UNLOCK, 30, 18, PASS, SERVER },
+ {12, CMD_UNLOCK, 50, 10, PASS, SERVER },
-/* SECTION 3: Overlapping READ and WRITE and UNLOCK with the different processes (CLIENT/SERVER) */
+/* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
/* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
- {13, WRLOCK, 10, 10, PASS, SERVER },
- {13, WRLOCK, 30, 10, PASS, SERVER },
- {13, RDLOCK, 50, 10, PASS, SERVER },
+ {13, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {13, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {13, CMD_RDLOCK, 50, 10, PASS, SERVER },
/* Same lock type, different process */
- {13, WRLOCK, 30, 10, FAIL, CLIENT },
- {13, RDLOCK, 50, 10, PASS, CLIENT },
+ {13, CMD_WRLOCK, 30, 10, FAIL, CLIENT },
+ {13, CMD_RDLOCK, 50, 10, PASS, CLIENT },
/* Exact match - different lock type, different process */
- {13, RDLOCK, 30, 10, FAIL, CLIENT },
+ {13, CMD_RDLOCK, 30, 10, FAIL, CLIENT },
/* Exact match - unlock */
- {13, UNLOCK, 30, 10, PASS, CLIENT },
+ {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
/* New lock - as above, inserting in the list again */
- {13, UNLOCK, 30, 10, PASS, SERVER },
+ {13, CMD_UNLOCK, 30, 10, PASS, SERVER },
/* Exact match - same lock type, different process */
- {13, WRLOCK, 30, 10, PASS, CLIENT },
+ {13, CMD_WRLOCK, 30, 10, PASS, CLIENT },
- {13, UNLOCK, 10, 10, PASS, SERVER },
- {13, UNLOCK, 30, 10, PASS, CLIENT },
- {13, UNLOCK, 50, 10, PASS, SERVER },
+ {13, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
+ {13, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
- {14, WRLOCK, 10, 10, PASS, SERVER },
- {14, WRLOCK, 30, 10, PASS, SERVER },
- {14, RDLOCK, 50, 10, PASS, SERVER },
+ {14, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {14, CMD_WRLOCK, 30, 10, PASS, SERVER },
+ {14, CMD_RDLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end overlaps */
- {14, RDLOCK, 30, 15, FAIL, CLIENT },
- {14, WRLOCK, 30, 15, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 30, 15, FAIL, CLIENT },
+ {14, CMD_WRLOCK, 30, 15, FAIL, CLIENT },
/* The start is before, end is the same */
- {14, RDLOCK, 25, 20, FAIL, CLIENT },
- {14, WRLOCK, 25, 20, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 25, 20, FAIL, CLIENT },
+ {14, CMD_WRLOCK, 25, 20, FAIL, CLIENT },
/* Both start and end overlap */
- {14, RDLOCK, 22, 26, FAIL, CLIENT },
- {14, WRLOCK, 22, 26, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 22, 26, FAIL, CLIENT },
+ {14, CMD_WRLOCK, 22, 26, FAIL, CLIENT },
/* The start is the same, end overlaps */
- {14, RDLOCK, 50, 15, PASS, CLIENT },
- {14, WRLOCK, 50, 17, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 50, 15, PASS, CLIENT },
+ {14, CMD_WRLOCK, 50, 17, FAIL, CLIENT },
/* The start is before, end is the same */
- {14, RDLOCK, 45, 20, PASS, CLIENT },
- {14, WRLOCK, 43, 22, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 45, 20, PASS, CLIENT },
+ {14, CMD_WRLOCK, 43, 22, FAIL, CLIENT },
/* Both start and end overlap */
- {14, RDLOCK, 42, 26, PASS, CLIENT },
- {14, WRLOCK, 41, 28, FAIL, CLIENT },
+ {14, CMD_RDLOCK, 42, 26, PASS, CLIENT },
+ {14, CMD_WRLOCK, 41, 28, FAIL, CLIENT },
- {14, UNLOCK, 10, 10, PASS, SERVER },
- {14, UNLOCK, 22, 26, PASS, SERVER },
- {14, UNLOCK, 42, 26, PASS, CLIENT },
+ {14, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {14, CMD_UNLOCK, 22, 26, PASS, SERVER },
+ {14, CMD_UNLOCK, 42, 26, PASS, CLIENT },
/* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
- {15, WRLOCK, 10, 10, PASS, SERVER },
- {15, RDLOCK, 30, 10, PASS, SERVER },
- {15, WRLOCK, 50, 10, PASS, SERVER },
+ {15, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {15, CMD_RDLOCK, 30, 10, PASS, SERVER },
+ {15, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* The start is the same, end is in the middle of old lock */
- {15, RDLOCK, 50, 5, FAIL, CLIENT },
- {15, WRLOCK, 50, 5, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 50, 5, FAIL, CLIENT },
+ {15, CMD_WRLOCK, 50, 5, FAIL, CLIENT },
/* The start and end are in the middle of old lock */
- {15, RDLOCK, 52, 6, FAIL, CLIENT },
- {15, WRLOCK, 52, 6, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 52, 6, FAIL, CLIENT },
+ {15, CMD_WRLOCK, 52, 6, FAIL, CLIENT },
/* Start in the middle and end is the same */
- {15, RDLOCK, 52, 8, FAIL, CLIENT },
- {15, WRLOCK, 52, 8, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 52, 8, FAIL, CLIENT },
+ {15, CMD_WRLOCK, 52, 8, FAIL, CLIENT },
/* The start is the same, end is in the middle of old lock */
- {15, RDLOCK, 30, 5, PASS, CLIENT },
- {15, WRLOCK, 30, 5, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 30, 5, PASS, CLIENT },
+ {15, CMD_WRLOCK, 30, 5, FAIL, CLIENT },
/* The start and end are in the middle of old lock */
- {15, RDLOCK, 32, 6, PASS, CLIENT },
- {15, WRLOCK, 32, 6, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 32, 6, PASS, CLIENT },
+ {15, CMD_WRLOCK, 32, 6, FAIL, CLIENT },
/* Start in the middle and end is the same */
- {15, RDLOCK, 32, 8, PASS, CLIENT },
- {15, WRLOCK, 32, 8, FAIL, CLIENT },
+ {15, CMD_RDLOCK, 32, 8, PASS, CLIENT },
+ {15, CMD_WRLOCK, 32, 8, FAIL, CLIENT },
- {15, UNLOCK, 10, 10, PASS, SERVER },
- {15, UNLOCK, 30, 10, PASS, SERVER },
- {15, UNLOCK, 50, 10, PASS, SERVER },
+ {15, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {15, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {15, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
- {16, RDLOCK, 10, 10, PASS, SERVER },
- {16, WRLOCK, 50, 10, PASS, SERVER },
+ {16, CMD_RDLOCK, 10, 10, PASS, SERVER },
+ {16, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Start is before, end is the start of the old lock in list */
- {16, RDLOCK, 5, 6, PASS, CLIENT },
- {16, WRLOCK, 5, 6, FAIL, CLIENT },
+ {16, CMD_RDLOCK, 5, 6, PASS, CLIENT },
+ {16, CMD_WRLOCK, 5, 6, FAIL, CLIENT },
/* Start is before, end is in the middle of the old lock */
- {16, RDLOCK, 5, 10, PASS, CLIENT },
- {16, WRLOCK, 5, 10, FAIL, CLIENT },
+ {16, CMD_RDLOCK, 5, 10, PASS, CLIENT },
+ {16, CMD_WRLOCK, 5, 10, FAIL, CLIENT },
/* Start is before, end is the start of the old lock in list */
- {16, RDLOCK, 45, 6, FAIL, CLIENT },
- {16, WRLOCK, 45, 6, FAIL, CLIENT },
+ {16, CMD_RDLOCK, 45, 6, FAIL, CLIENT },
+ {16, CMD_WRLOCK, 45, 6, FAIL, CLIENT },
/* Start is before, end is in the middle of the old lock */
- {16, RDLOCK, 45, 10, FAIL, CLIENT },
- {16, WRLOCK, 45, 10, FAIL, CLIENT },
+ {16, CMD_RDLOCK, 45, 10, FAIL, CLIENT },
+ {16, CMD_WRLOCK, 45, 10, FAIL, CLIENT },
- {16, UNLOCK, 5, 15, PASS, CLIENT },
- {16, UNLOCK, 30, 10, PASS, SERVER },
- {16, UNLOCK, 50, 10, PASS, SERVER },
+ {16, CMD_UNLOCK, 5, 15, PASS, CLIENT },
+ {16, CMD_UNLOCK, 30, 10, PASS, SERVER },
+ {16, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
- {17, WRLOCK, 10, 10, PASS, SERVER },
- {17, RDLOCK, 30, 10, PASS, SERVER },
- {17, WRLOCK, 50, 10, PASS, SERVER },
+ {17, CMD_WRLOCK, 10, 10, PASS, SERVER },
+ {17, CMD_RDLOCK, 30, 10, PASS, SERVER },
+ {17, CMD_WRLOCK, 50, 10, PASS, SERVER },
/* Start in the middle, end after lock in list */
- {17, WRLOCK, 35, 10, FAIL, CLIENT },
+ {17, CMD_WRLOCK, 35, 10, FAIL, CLIENT },
/* Start matches end of lock in list */
- {17, RDLOCK, 35, 10, PASS, CLIENT },
- {17, RDLOCK, 44, 2, PASS, CLIENT },
+ {17, CMD_RDLOCK, 35, 10, PASS, CLIENT },
+ {17, CMD_RDLOCK, 44, 2, PASS, CLIENT },
/* Start in the middle, end after lock in list */
- {17, RDLOCK, 55, 10, FAIL, CLIENT },
- {17, WRLOCK, 55, 10, FAIL, CLIENT },
+ {17, CMD_RDLOCK, 55, 10, FAIL, CLIENT },
+ {17, CMD_WRLOCK, 55, 10, FAIL, CLIENT },
/* Start matches end of lock in list */
- {17, RDLOCK, 59, 5, FAIL, CLIENT },
- {17, WRLOCK, 59, 5, FAIL, CLIENT },
+ {17, CMD_RDLOCK, 59, 5, FAIL, CLIENT },
+ {17, CMD_WRLOCK, 59, 5, FAIL, CLIENT },
- {17, UNLOCK, 10, 10, PASS, SERVER },
- {17, UNLOCK, 30, 16, PASS, CLIENT },
- {17, UNLOCK, 50, 10, PASS, SERVER },
+ {17, CMD_UNLOCK, 10, 10, PASS, SERVER },
+ {17, CMD_UNLOCK, 30, 16, PASS, CLIENT },
+ {17, CMD_UNLOCK, 50, 10, PASS, SERVER },
/* SECTION 4: overlapping and EOF tests */
/* Acquire overlapping ranges */
- {18, WRLOCK, 11, 7, PASS, SERVER },
- {18, WRLOCK, 13, 8, FAIL, CLIENT },
- {18, UNLOCK, 11, 7, PASS, SERVER },
+ {18, CMD_WRLOCK, 11, 7, PASS, SERVER },
+ {18, CMD_WRLOCK, 13, 8, FAIL, CLIENT },
+ {18, CMD_UNLOCK, 11, 7, PASS, SERVER },
/* Acquire different ranges beyond EOF */
- {19, WRLOCK, 10, FILE_SIZE, PASS, SERVER },
- {19, WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
- {19, UNLOCK, 10, FILE_SIZE, PASS, SERVER },
- {19, UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
+ {19, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER },
+ {19, CMD_WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
+ {19, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER },
+ {19, CMD_UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
/* Acquire same range beyong EOF */
- {20, WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
- {20, WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
- {20, UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
+ {20, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
+ {20, CMD_WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
+ {20, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
/* Acquire whole file lock */
- {21, WRLOCK, 0, 0, PASS, SERVER, },
- {21, WRLOCK, 0, 0, FAIL, CLIENT, },
- {21, UNLOCK, 0, 0, PASS, SERVER, },
+ {21, CMD_WRLOCK, 0, 0, PASS, SERVER, },
+ {21, CMD_WRLOCK, 0, 0, FAIL, CLIENT, },
+ {21, CMD_UNLOCK, 0, 0, PASS, SERVER, },
/* Acquire whole file lock, then range */
- {22, WRLOCK, 0, 0, PASS, SERVER, },
- {22, WRLOCK, 1, 5, FAIL, CLIENT, },
- {22, UNLOCK, 0, 0, PASS, SERVER, },
+ {22, CMD_WRLOCK, 0, 0, PASS, SERVER, },
+ {22, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
+ {22, CMD_UNLOCK, 0, 0, PASS, SERVER, },
/* Acquire non-overlapping read locks */
- {23, RDLOCK, 1, 5, PASS, SERVER, },
- {23, RDLOCK, 7, 6, PASS, CLIENT, },
- {23, UNLOCK, 1, 5, PASS, SERVER, },
- {23, UNLOCK, 7, 6, PASS, CLIENT, },
+ {23, CMD_RDLOCK, 1, 5, PASS, SERVER, },
+ {23, CMD_RDLOCK, 7, 6, PASS, CLIENT, },
+ {23, CMD_UNLOCK, 1, 5, PASS, SERVER, },
+ {23, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
/* Acquire overlapping read locks */
- {24, RDLOCK, 1, 5, PASS, SERVER, },
- {24, RDLOCK, 2, 6, PASS, CLIENT, },
- {24, UNLOCK, 1, 5, PASS, SERVER, },
- {24, UNLOCK, 1, 7, PASS, CLIENT, },
+ {24, CMD_RDLOCK, 1, 5, PASS, SERVER, },
+ {24, CMD_RDLOCK, 2, 6, PASS, CLIENT, },
+ {24, CMD_UNLOCK, 1, 5, PASS, SERVER, },
+ {24, CMD_UNLOCK, 1, 7, PASS, CLIENT, },
/* Acquire non-overlapping read and write locks */
- {25, RDLOCK, 1, 5, PASS, SERVER, },
- {25, WRLOCK, 7, 6, PASS, CLIENT, },
- {25, UNLOCK, 1, 5, PASS, SERVER, },
- {25, UNLOCK, 7, 6, PASS, CLIENT, },
+ {25, CMD_RDLOCK, 1, 5, PASS, SERVER, },
+ {25, CMD_WRLOCK, 7, 6, PASS, CLIENT, },
+ {25, CMD_UNLOCK, 1, 5, PASS, SERVER, },
+ {25, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
/* Acquire overlapping read and write locks */
- {26, RDLOCK, 1, 5, PASS, SERVER, },
- {26, WRLOCK, 2, 6, FAIL, CLIENT, },
- {26, UNLOCK, 1, 5, PASS, SERVER, },
+ {26, CMD_RDLOCK, 1, 5, PASS, SERVER, },
+ {26, CMD_WRLOCK, 2, 6, FAIL, CLIENT, },
+ {26, CMD_UNLOCK, 1, 5, PASS, SERVER, },
/* Acquire whole file lock, then close (without unlocking) */
- {27, WRLOCK, 0, 0, PASS, SERVER, },
- {27, WRLOCK, 1, 5, FAIL, CLIENT, },
- {27, F_CLOSE,0, 0, PASS, SERVER, },
- {27, WRLOCK, 1, 5, PASS, CLIENT, },
- {27, F_OPEN, 0, 0, PASS, SERVER, },
- {27, UNLOCK, 1, 5, PASS, CLIENT, },
+ {27, CMD_WRLOCK, 0, 0, PASS, SERVER, },
+ {27, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
+ {27, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {27, CMD_WRLOCK, 1, 5, PASS, CLIENT, },
+ {27, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
+ {27, CMD_UNLOCK, 1, 5, PASS, CLIENT, },
/* Acquire two read locks, close one file and then reopen to check that first lock still exists */
- {28, RDLOCK, 1, 5, PASS, SERVER, },
- {28, RDLOCK, 1, 5, PASS, CLIENT, },
- {28, F_CLOSE,0, 0, PASS, SERVER, },
- {28, F_OPEN, 0, 0, PASS, SERVER, },
- {28, WRLOCK, 0, 0, FAIL, SERVER, },
- {28, UNLOCK, 1, 5, PASS, SERVER, },
+ {28, CMD_RDLOCK, 1, 5, PASS, SERVER, },
+ {28, CMD_RDLOCK, 1, 5, PASS, CLIENT, },
+ {28, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {28, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
+ {28, CMD_WRLOCK, 0, 0, FAIL, SERVER, },
+ {28, CMD_UNLOCK, 1, 5, PASS, SERVER, },
+ /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
+ {29, CMD_CLOSE, 0, 0, PASS, SERVER, },
+ {29, CMD_OPEN, O_RDONLY, 0, PASS, SERVER, },
+ {29, CMD_WRTEST, 0, 0, PASS, SERVER, },
+ {29, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {29, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
#ifdef macosx
/* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
- {29, F_CLOSE,0, 0, PASS, SERVER, },
- {29, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
- {29, F_CLOSE,0, 0, PASS, CLIENT, },
- {29, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
+ {30, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
+ {30, CMD_CLOSE,0, 0, PASS, CLIENT, },
+ {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
/* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
- {30, F_CLOSE,0, 0, PASS, SERVER, },
- {30, F_CLOSE,0, 0, PASS, CLIENT, },
- {30, F_OPEN, O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
- {30, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
+ {31, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {31, CMD_CLOSE,0, 0, PASS, CLIENT, },
+ {31, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
+ {31, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
/* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
- {31, F_CLOSE,0, 0, PASS, SERVER, },
- {31, F_CLOSE,0, 0, FAIL, CLIENT, },
- {31, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
- {31, F_OPEN, O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
- {31, F_CLOSE,0, 0, PASS, SERVER, },
- {31, F_CLOSE,0, 0, FAIL, CLIENT, },
- {31, F_OPEN, 0, 0, PASS, SERVER, },
- {31, F_OPEN, 0, 0, PASS, CLIENT, },
+ {32, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
+ {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
+ {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
+ {32, CMD_CLOSE,0, 0, PASS, SERVER, },
+ {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
+ {32, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
+ {32, CMD_OPEN, O_RDWR, 0, PASS, CLIENT, },
#endif /* macosx */
+
+ /* indicate end of array */
+ {0,0,0,0,0,SERVER},
+ {0,0,0,0,0,CLIENT}
+ };
+
+
+char *lease_descriptions[] = {
+ /* 1 */"Take Read Lease",
+ /* 2 */"Take Write Lease",
+ /* 3 */"Fail Write Lease if file is open somewhere else",
+ /* 4 */"Fail Read Lease if opened with write permissions",
+ /* 5 */"Read lease gets SIGIO on write open",
+ /* 6 */"Write lease gets SIGIO on read open",
+ /* 7 */"Read lease does _not_ get SIGIO on read open",
+ /* 8 */"Read lease gets SIGIO on write open",
+};
+
+static int64_t lease_tests[][6] =
+ /* test # Action [offset|flags|arg] length expected server/client */
+ /* [sigio_wait_time] */
+ {
+ /* Various tests to exercise leases */
+
+/* SECTION 1: Simple verification of being able to take leases */
+ /* Take Read Lease */
+ {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
+ {1, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {1, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {1, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {1, CMD_SETLEASE, F_RDLCK, 0, PASS, SERVER },
+ {1, CMD_GETLEASE, F_RDLCK, 0, PASS, SERVER },
+ {1, CMD_SETLEASE, F_UNLCK, 0, PASS, SERVER },
+ {1, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Take Write Lease */
+ {2, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {2, CMD_SETLEASE, F_WRLCK, 0, PASS, SERVER },
+ {2, CMD_GETLEASE, F_WRLCK, 0, PASS, SERVER },
+ {2, CMD_SETLEASE, F_UNLCK, 0, PASS, SERVER },
+ {2, CMD_CLOSE, 0, 0, PASS, SERVER },
+ /* Fail Write Lease with other users */
+ {3, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {3, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {3, CMD_SETLEASE, F_WRLCK, 0, FAIL, SERVER },
+ {3, CMD_GETLEASE, F_WRLCK, 0, FAIL, SERVER },
+ {3, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {3, CMD_CLOSE, 0, 0, PASS, CLIENT },
+ /* Fail Read Lease if opened for write */
+ {4, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {4, CMD_SETLEASE, F_RDLCK, 0, FAIL, SERVER },
+ {4, CMD_GETLEASE, F_RDLCK, 0, FAIL, SERVER },
+ {4, CMD_CLOSE, 0, 0, PASS, SERVER },
+
+/* SECTION 2: Proper SIGIO notifications */
+ /* Get SIGIO when read lease is broken by write */
+ {5, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {5, CMD_SETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {5, CMD_GETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {5, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {5, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {5, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {5, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {5, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when write lease is broken by read */
+ {6, CMD_OPEN, O_RDWR, 0, PASS, CLIENT },
+ {6, CMD_SETLEASE, F_WRLCK, 0, PASS, CLIENT },
+ {6, CMD_GETLEASE, F_WRLCK, 0, PASS, CLIENT },
+ {6, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {6, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {6, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {6, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {6, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Don't get SIGIO when read lease is taken by read */
+ {7, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {7, CMD_SETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {7, CMD_GETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {7, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {7, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
+ {7, CMD_WAIT_SIGIO, 5, 0, FAIL, CLIENT },
+ {7, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {7, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
+ /* Get SIGIO when Read lease is broken by Write */
+ {8, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
+ {8, CMD_SETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {8, CMD_GETLEASE, F_RDLCK, 0, PASS, CLIENT },
+ {8, CMD_SIGIO, 0, 0, PASS, CLIENT },
+ {8, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
+ {8, CMD_WAIT_SIGIO, 5, 0, PASS, CLIENT },
+ {8, CMD_CLOSE, 0, 0, PASS, SERVER },
+ {8, CMD_CLOSE, 0, 0, PASS, CLIENT },
+
/* indicate end of array */
{0,0,0,0,0,SERVER},
{0,0,0,0,0,CLIENT}
int offset = 0;
int togo = FILE_SIZE;
- if (D_flag) {
- ibuf = (char *)ALLOC_ALIGNED(INIT_BUFSZ);
- }
- else {
- ibuf = (char*)malloc(INIT_BUFSZ);
- }
+ ibuf = (char*)malloc(INIT_BUFSZ);
memset(ibuf, ':', INIT_BUFSZ);
SEEK(fd, 0L);
}
}
+void release_lease(int fd)
+{
+ int rc;
-int do_open(int flag)
+ rc = fcntl(fd, F_SETLEASE, F_UNLCK);
+ if (rc != 0)
+ fprintf(stderr, "%s Failed to remove lease %d : %d %s\n",
+ __FILE__, rc, errno, strerror(errno));
+}
+
+void lease_break(int sig, siginfo_t *info, void *p)
{
- if ((f_fd = OPEN(filename, flag)) == INVALID_HANDLE) {
- perror("shared file create");
- if (!flag) /* Only exit if the first open fails */
- exit(1);
- closed = 0;
+ if (debug)
+ fprintf(stderr, "lease break %d %p fd %d\n",
+ sig, info, info->si_fd);
+ got_sigio = 1;
+ release_lease(f_fd);
+}
+
+struct sigaction lease_break_action = {
+ .sa_sigaction = lease_break,
+ .sa_flags = SA_SIGINFO,
+};
+
+int do_setup_sigio(int fd)
+{
+ int rc;
+
+ got_sigio = 0;
+
+ rc = sigaction(SIGIO, &lease_break_action, NULL);
+ if (rc != 0) {
+ fprintf(stderr, "%s Set '%s' sigaction failed %d\n",
+ __FILE__, strsignal(SIGIO), rc);
+ return FAIL;
+ }
+
+ if (debug)
+ fprintf(stderr, "Set '%s' sigaction on %d\n",
+ strsignal(SIGIO), fd);
+
+ rc = fcntl(fd, F_SETSIG, SIGIO);
+ if (rc)
+ fprintf(stderr, "%s Set '%s' sigaction failed %d\n",
+ __FILE__, strsignal(SIGIO), rc);
+
+ return (rc == 0 ? PASS : FAIL);
+}
+
+int do_wait_sigio(int32_t time)
+{
+ if (time <= 0)
return FAIL;
- /*NOTREACHED*/
+
+ while (!got_sigio && time--) {
+ sleep(1);
}
- closed = 0;
+ if (debug > 1 && !got_sigio)
+ fprintf(stderr, "%s failed to get sigio\n",
+ __FILE__);
-#ifdef __sun
- if (D_flag) {
- directio(f_fd, DIRECTIO_ON);
- }
-#elif defined(__APPLE__)
- if (D_flag) {
- fcntl(f_fd, F_NOCACHE, 1);
+ return (got_sigio ? PASS: FAIL);
+}
+
+int do_open(int flag)
+{
+ int flags = flag|O_CREAT|O_BINARY;
+
+ if(debug > 1)
+ fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
+
+ if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
+ perror("shared file create");
+ return FAIL;
+ /*NOTREACHED*/
}
-#endif
return PASS;
}
-int do_lock(int type, int start, int length)
+static int do_lock(int cmd, int type, int start, int length)
{
int ret;
int filedes = f_fd;
struct flock fl;
if(debug > 1) {
- fprintf(stderr, "do_lock: start=%d, length=%d\n", start, length);
+ fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
}
if (f_fd < 0)
errno = 0;
- ret = fcntl(filedes, F_SETLK, &fl);
+ ret = fcntl(filedes, cmd, &fl);
saved_errno = errno;
- if(debug > 1 && ret)
+ if(ret)
fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
return(ret==0?PASS:FAIL);
}
-int do_unlock(int start, int length)
+static int do_lease(int cmd, int arg, int expected)
{
int ret;
- int filedes = f_fd;
- struct flock fl;
- if(debug > 1) {
- fprintf(stderr, "do_unlock: start=%d, length=%d\n", start, length);
- }
+ if(debug > 1)
+ fprintf(stderr, "do_lease: cmd=%d arg=%d exp=%X\n",
+ cmd, arg, expected);
if (f_fd < 0)
return f_fd;
-
- fl.l_start = start;
- fl.l_len = length;
- fl.l_whence = SEEK_SET;
- fl.l_pid = getpid();
- fl.l_type = F_UNLCK;
errno = 0;
- ret = fcntl(filedes, F_SETLK, &fl);
- saved_errno = errno;
- if(debug > 1 && ret)
- fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
+ ret = fcntl(f_fd, cmd, arg);
+ saved_errno = errno;
+
+ if (expected && (expected == ret))
+ ret = 0;
+
+ if(ret)
+ fprintf(stderr, "%s do_lease: ret = %d, errno = %d (%s)\n",
+ __FILE__, ret, errno, strerror(errno));
return(ret==0?PASS:FAIL);
}
errno =0;
CLOSE(f_fd);
+ f_fd = INVALID_HANDLE;
saved_errno = errno;
- if (errno)
+ if (errno) {
+ fprintf(stderr, "%s errno = %d (%s)\n",
+ __FILE__, errno, strerror(errno));
return FAIL;
- return(PASS);
+ }
+ return PASS;
+}
+
+static void init_ctl(int64_t tests[][6], int32_t index)
+{
+ ctl.test= (int32_t)tests[index][TEST_NUM];
+ ctl.command = (int32_t)tests[index][COMMAND];
+ ctl.offset = tests[index][OFFSET];
+ ctl.length = tests[index][LENGTH];
+ ctl.index = index;
+ ctl.result = (int32_t)tests[index][RESULT];
+ ctl.error = 0;
}
void
{
int nwrite;
- if (debug > 1) {
+ if (debug) {
fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
}
{
int nread;
+again:
if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
- if (nread < 0)
+ if (nread < 0) {
+ if (errno == EINTR)
+ goto again;
perror("recv_ctl: read");
- else {
+ } else {
fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",
ctl.test, nread, sizeof(ctl));
fprintf(stderr, "socket might has been closed by other locktest\n");
ctl.index= bswap_uint32(ctl.index);
ctl.error= bswap_uint32(ctl.error);
- if (debug > 1) {
+ if (debug) {
fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
}
void
cleanup(void)
{
- if (f_fd>=0 && !reopen && !closed)
+ if (f_fd>=0)
CLOSE(f_fd);
if (c_fd>=0)
PLATFORM_CLEANUP();
}
+int
+run(int64_t tests[][6], char *descriptions[]);
+
int
main(int argc, char *argv[])
{
char *p;
extern char *optarg;
extern int optind;
- extern int errno;
- int fail_count = 0;;
+ int fail_count = 0;
+ int run_leases = 0;
atexit(cleanup);
prog = p+1;
}
- while ((c = getopt(argc, argv, "dn:h:p:?")) != EOF) {
+ while ((c = getopt(argc, argv, "dLn:h:p:?")) != EOF) {
switch (c) {
case 'd': /* debug flag */
debug++;
break;
+ case 'L': /* Lease testing */
+ run_leases = 1;
+ break;
+
case 'h': /* (server) hostname */
server = 0;
host = optarg;
}
filename=argv[optind];
- do_open(0);
-
- /*
- * +10 is slop for the iteration number if do_write() ... never
- * needed unless maxio is very small
- */
- if (D_flag) {
- if ((buf = (char *)ALLOC_ALIGNED(maxio + 10)) == NULL) {
- perror("aligned alloc buf");
- exit(1);
- /*NOTREACHED*/
- }
- } else {
- if ((buf = (char *)malloc(maxio + 10)) == NULL) {
- perror("malloc buf");
- exit(1);
- /*NOTREACHED*/
- }
- }
+ if (debug)
+ fprintf(stderr, "Working on file : %s\n", filename);
+ if (do_open(O_RDWR) == FAIL)
+ exit(1);
setbuf(stderr, NULL);
/*NOTREACHED*/
}
+ if (port == 0) {
+ socklen_t addr_len = sizeof(myAddr);
+
+ if (getsockname(s_fd, &myAddr, &addr_len)) {
+ perror("getsockname");
+ exit(1);
+ }
+
+ port = ntohs(myAddr.sin_port);
+ }
+
+ printf("server port: %d\n", port);
+ fflush(stdout);
+
c_fd = accept(s_fd, NULL, NULL);
if (c_fd == INVALID_SOCKET) {
perror("accept");
struct hostent *servInfo;
if ((servInfo = gethostbyname(host)) == NULL) {
- printf("Couldn't get hostbyname for %s", host);
+ fprintf(stderr, "Couldn't get hostbyname for %s", host);
if (h_errno == HOST_NOT_FOUND)
- printf(": host not found");
- printf("\n");
+ fprintf(stderr, ": host not found");
+ fprintf(stderr, "\n");
exit(1);
/*NOTREACHED*/
}
*
* real work is in here ...
*/
- i = 0;
+ if (run_leases)
+ fail_count = run(lease_tests, lease_descriptions);
+ else
+ fail_count = run(lock_tests, lock_descriptions);
+
+ exit(fail_count);
+ /*NOTREACHED*/
+}
+
+int run(int64_t tests[][6], char *descriptions[])
{
int index = 0;
int end = 0;
int result = 0;
int last_test = 0;
- int test_count = 0;
+ int test_count = -1;
int fail_flag = 0;
+ int fail_count = 0;
while(!end) {
if (server) {
if(testnumber > 0) {
}
/* If we have a server command, deal with it */
if(tests[index][WHO] == SERVER) {
- if(debug>1)
+ if(debug)
fprintf(stderr, "Got a server command (%d)\n", index);
if(tests[index][TEST_NUM] == 0) {
index++;
if(tests[index][TEST_NUM] != 0) {
switch(tests[index][COMMAND]) {
- case WRLOCK:
- result = do_lock(F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ case CMD_WRLOCK:
+ result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
break;
- case RDLOCK:
- result = do_lock(F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ case CMD_RDLOCK:
+ result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
break;
- case UNLOCK:
- result = do_unlock(tests[index][OFFSET], tests[index][LENGTH]);
+ case CMD_UNLOCK:
+ result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
break;
- case F_CLOSE:
+ case CMD_CLOSE:
result = do_close();
break;
- case F_OPEN:
+ case CMD_OPEN:
result = do_open(tests[index][FLAGS]);
break;
+ case CMD_WRTEST:
+ result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ break;
+ case CMD_RDTEST:
+ result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ break;
+ case CMD_SETLEASE:
+ result = do_lease(F_SETLEASE, tests[index][ARG], 0);
+ break;
+ case CMD_GETLEASE:
+ result = do_lease(F_GETLEASE, tests[index][ARG], tests[index][ARG]);
+ break;
+ case CMD_SIGIO:
+ result = do_setup_sigio(f_fd);
+ break;
+ case CMD_WAIT_SIGIO:
+ result = do_wait_sigio(tests[index][TIME]);
+ break;
}
if( result != tests[index][RESULT]) {
fail_flag++;
/* We have a failure */
- if(debug)
- fprintf(stderr, "Server failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
- ctl.test, tests[index][COMMAND]==WRLOCK?"write lock":
- tests[index][COMMAND]==RDLOCK?"read lock":
- tests[index][COMMAND]==UNLOCK?"unlock":
- tests[index][COMMAND]==F_OPEN?"open":"clos",
- (long long)tests[index][OFFSET],
- (long long)tests[index][LENGTH],
- saved_errno, strerror(saved_errno));
- fprintf(stderr, "Server failure in %lld:%s\n",
- (long long)tests[index][TEST_NUM],
- descriptions[tests[index][TEST_NUM] - 1]);
+ fprintf(stderr, " ***** Server failure *****\n");
+ fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
+ ctl.test, get_cmd_str(tests[index][COMMAND]),
+ (long long)tests[index][OFFSET],
+ (long long)tests[index][LENGTH],
+ saved_errno, strerror(saved_errno));
+ fprintf(stderr, " %d:%s\n",
+ ctl.test, descriptions[ctl.test - 1]);
}
}
/* else send it off to the client */
ctl.test = 0;
end=1;
}
- if(debug > 1)
+ /* get the client to do something */
+ init_ctl(tests, index);
+ if(debug)
fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
- index, tests[index][COMMAND]==WRLOCK?"write lock":
- tests[index][COMMAND]==RDLOCK?"read lock":
- tests[index][COMMAND]==UNLOCK?"unlock":
- tests[index][COMMAND]==F_OPEN?"open":"clos",
+ index,
+ get_cmd_str(ctl.command),
(long long)tests[index][OFFSET],
(long long)tests[index][LENGTH]);
/* get the client to do something */
* not what the command returned */
if( ctl.result == FAIL ) {
fail_flag++;
- if(debug)
- fprintf(stderr, "Client failure in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
- ctl.test, ctl.command==WRLOCK?"write lock":
- ctl.command==RDLOCK?"read lock":
- ctl.command==UNLOCK?"unlock":
- ctl.command==F_OPEN?"open":"clos",
+ fprintf(stderr, " ***** Client failure *****\n");
+ fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
+ ctl.test, get_cmd_str(ctl.command),
(long long)ctl.offset, (long long)ctl.length,
ctl.error, strerror(ctl.error));
- fprintf(stderr, "Client failure in %lld:%s\n",
- (long long)tests[index][TEST_NUM],
- descriptions[tests[index][TEST_NUM] - 1]);
+ fprintf(stderr, " %d:%s\n",
+ ctl.test, descriptions[ctl.test - 1]);
}
}
}
- if (debug > 1) {
- fprintf(stderr, "server sleeping ...\n");
- SLEEP(1);
- }
- if(tests[index][TEST_NUM] != 0) {
- if(last_test != tests[index][TEST_NUM]) {
- test_count++;
- if(fail_flag)
- fail_count++;
- fail_flag = 0;
- }
- last_test = tests[index][TEST_NUM];
+ if(last_test != tests[index][TEST_NUM]) {
+ test_count++;
+ if(fail_flag)
+ fail_count++;
+ fail_flag = 0;
+ last_test = tests[index][TEST_NUM];
}
index++;
} else { /* CLIENT */
- if(debug > 2)
+ if(debug)
fprintf(stderr,"client: waiting...\n");
/* wait for the server to do something */
recv_ctl();
end = 1;
break;
}
-
- ctl.command = tests[index][COMMAND];
- ctl.offset = tests[index][OFFSET];
- ctl.length = tests[index][LENGTH];
- switch(tests[index][COMMAND]) {
- case WRLOCK:
- result = do_lock(F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ switch(ctl.command) {
+ case CMD_WRLOCK:
+ result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length);
break;
- case RDLOCK:
- result = do_lock(F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
+ case CMD_RDLOCK:
+ result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length);
break;
- case UNLOCK:
- result = do_unlock(tests[index][OFFSET], tests[index][LENGTH]);
+ case CMD_UNLOCK:
+ result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length);
break;
- case F_CLOSE:
+ case CMD_CLOSE:
result = do_close();
break;
- case F_OPEN:
+ case CMD_OPEN:
result = do_open(tests[index][FLAGS]);
break;
+ case CMD_WRTEST:
+ result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length);
+ break;
+ case CMD_RDTEST:
+ result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length);
+ break;
+ /* NOTE offset carries the argument values */
+ case CMD_SETLEASE:
+ result = do_lease(F_SETLEASE, ctl.offset, 0);
+ break;
+ case CMD_GETLEASE:
+ result = do_lease(F_GETLEASE, ctl.offset, ctl.offset);
+ break;
+ case CMD_SIGIO:
+ result = do_setup_sigio(f_fd);
+ break;
+ case CMD_WAIT_SIGIO:
+ result = do_wait_sigio(ctl.offset);
+ break;
}
- if( result != tests[index][RESULT] ) {
- if(debug)
- fprintf(stderr,"Got %d, wanted %lld\n", result,
- (long long)tests[index][RESULT]);
+ if( result != ctl.result ) {
+ fprintf(stderr,"Failure in %d:%s\n",
+ ctl.test, descriptions[ctl.test - 1]);
+ fprintf(stderr," Got %d, wanted %d\n",
+ result, ctl.result);
ctl.result = FAIL;
ctl.error = saved_errno;
fail_count++;
} else {
ctl.result = PASS;
+ ctl.error = 0;
}
- if(debug > 2)
+ if(debug)
fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
/* Send result to the server */
send_ctl();
- if(tests[index][TEST_NUM] != 0) {
- if(last_test != tests[index][TEST_NUM])
- test_count++;
+ if(last_test != tests[index][TEST_NUM]) {
+ test_count++;
last_test = tests[index][TEST_NUM];
}
}
}
- if(server)
- printf("%d tests run, %d failed\n", test_count, fail_count);
-}
- if (buf) {
- if (D_flag)
- FREE_ALIGNED(buf);
- else
- free(buf);
- }
+ fprintf(stderr, "%d tests run, %d failed\n", test_count, fail_count);
-
- exit(fail_count);
- /*NOTREACHED*/
+ return fail_count;
}
-
-