1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (c) 2000-2003 Silicon Graphics, Inc.
4 * Copyright (c) 2019 Intel Corp.
9 * Synchronized byte range lock and lease exerciser
19 #include <sys/socket.h>
20 #include <netinet/in.h>
21 #include <netinet/tcp.h>
24 #include <sys/types.h>
30 #define HEX_2_ASC(x) ((x) > 9) ? (x)-10+'a' : (x)+'0'
31 #define FILE_SIZE 1024
32 #define PLATFORM_INIT() /*no-op*/
33 #define PLATFORM_CLEANUP() /*no-op*/
38 #define inet_aton(STRING, INADDRP) \
39 (((INADDRP)->s_addr = inet_addr(STRING)) == -1 ? 0 : 1)
41 /* this assumes 32 bit pointers */
42 #define PTR_TO_U64(P) ((unsigned __int64)(unsigned int)(P))
43 #define U64_TO_PTR(T,U) ((T)(void *)(unsigned int)(U))
45 #if __BYTE_ORDER == __LITTLE_ENDIAN
46 #define bswap_uint16(x) (uint16_t)bswap_16(x)
47 #define bswap_uint32(x) (uint32_t)bswap_32(x)
48 #define bswap_uint64(x) (uint64_t)bswap_64(x)
50 #define bswap_uint16(x) x
51 #define bswap_uint32(x) x
52 #define bswap_uint64(x) x
56 #define SOCKET_READ read
57 #define SOCKET_WRITE write
58 #define SOCKET_CLOSE(S) (close(S))
59 #define INVALID_SOCKET -1
64 #define INVALID_HANDLE -1
65 #define SEEK(H, O) (lseek(H, O, SEEK_SET))
66 #define READ(H, B, L) (read(H, B, L))
67 #define WRITE(H, B, L) (write(H, B, L))
68 #define CLOSE(H) (close(H))
70 #define RAND() (rand())
71 #define SRAND(s) (srand(s))
73 #define MIN(A,B) (((A)<(B))?(A):(B))
74 #define MAX(A,B) (((A)>(B))?(A):(B))
76 #define ALLOC_ALIGNED(S) (memalign(65536, S))
77 #define FREE_ALIGNED(P) (free(P))
80 static char *filename = 0;
82 static int server = 1;
84 static int testnumber = -1;
85 static int saved_errno = 0;
87 static SOCKET s_fd = -1; /* listen socket */
88 static SOCKET c_fd = -1; /* IPC socket */
89 static HANDLE f_fd = INVALID_HANDLE; /* shared file */
98 #define CMD_SETLEASE 7
99 #define CMD_GETLEASE 8
113 #define FLAGS 2 /* index 2 is also used for do_open() flag, see below */
114 #define ARG FLAGS /* Arguments for Lease operations */
116 static char *get_cmd_str(int cmd)
119 case CMD_WRLOCK: return "write lock"; break;
120 case CMD_RDLOCK: return "read lock"; break;
121 case CMD_UNLOCK: return "unlock"; break;
122 case CMD_CLOSE: return "close"; break;
123 case CMD_OPEN: return "open"; break;
124 case CMD_WRTEST: return "Wait for SIGIO"; break;
125 case CMD_RDTEST: return "Truncate"; break;
126 case CMD_SETLEASE: return "Set Lease"; break;
127 case CMD_GETLEASE: return "Get Lease"; break;
132 * flags for Mac OS X do_open()
149 * When adding tests be sure to add to both the descriptions AND tests array.
150 * Also, be sure to undo whatever is set for each test (eg unlock any locks)
151 * There is no need to have a matching client command for each server command
155 char *lock_descriptions[] = {
156 /* 1 */"Add a lock to an empty lock list",
157 /* 2 */"Add a lock to the start and end of a list - no overlaps",
158 /* 3 */"Add a lock to the middle of a list - no overlap",
159 /* 4 */"Add different lock types to middle of the list - overlap exact match",
160 /* 5 */"Add new lock which completely overlaps any old lock in the list",
161 /* 6 */"Add new lock which itself is completely overlaped by any old lock in the list",
162 /* 7 */"Add new lock which starts before any old lock in the list",
163 /* 8 */"Add new lock which starts in the middle of any old lock in the list and ends after",
164 /* 9 */"Add different new lock types which completely overlaps any old lock in the list",
165 /* 10 */"Add different new locks which are completely overlaped by an old lock in the list",
166 /* 11 */"Add different new lock types which start before the old lock in the list",
167 /* 12 */"Add different new lock types which start in the middle of an old lock in the list and end after",
168 /* 13 */"Add new lock, differing types and processes, to middle of the list - exact overlap match",
169 /* 14 */"Add new lock, differing types and processes, which completely overlap any of the locks in the list",
170 /* 15 */"Add new lock, differing types and processes, which are completely overlaped by locks in the list",
171 /* 16 */"Add new lock, differing types and processes, which start before a lock in the list",
172 /* 17 */"Add new lock, differing types and processes, which starts in the middle of a lock, and ends after",
173 /* 18 */"Acquire write locks with overlapping ranges",
174 /* 19 */"Acquire write locks with non-overlapping ranges extending beyond EOF",
175 /* 20 */"Acquire write locks with overlapping ranges extending beyond EOF",
176 /* 21 */"Acquire write locks on whole files",
177 /* 22 */"Acquire write lock on whole file and range write lock",
178 /* 23 */"Acquire read locks with non-overlapping ranges",
179 /* 24 */"Acquire read locks with overlapping ranges",
180 /* 25 */"Acquire read and write locks with no overlapping ranges",
181 /* 26 */"Acquire read and write locks with overlapping ranges",
182 /* 27 */"Acquire whole file write lock and then close without unlocking (and attempt a lock)",
183 /* 28 */"Acquire two read locks, close and reopen the file, and test if the inital lock is still there",
184 /* 29 */"Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write",
186 /* 30 */"Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too",
187 /* 31 */"Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK",
188 /* 32 */"Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too"
192 static int64_t lock_tests[][6] =
193 /* test # Action [offset|flags] length expected server/client */
195 /* Various simple tests exercising the list */
197 /* SECTION 1: WRITE and CMD_UNLOCK with the same process (SERVER) */
198 /* Add a lock to an empty list */
199 {1, CMD_WRLOCK, 1, 10, PASS, SERVER },
200 {1, CMD_UNLOCK, 1, 10, PASS, SERVER },
202 /* Add a lock to the start and end of a list - 1, 13 - no overlap */
203 {2, CMD_WRLOCK, 10, 10, PASS, SERVER },
204 {2, CMD_WRLOCK, 30, 10, PASS, SERVER },
205 {2, CMD_WRLOCK, 50, 10, PASS, SERVER },
206 {2, CMD_WRLOCK, 1, 5, PASS, SERVER },
207 {2, CMD_WRLOCK, 70, 5, PASS, SERVER },
209 {2, CMD_UNLOCK, 10, 10, PASS, SERVER },
210 {2, CMD_UNLOCK, 30, 10, PASS, SERVER },
211 {2, CMD_UNLOCK, 50, 10, PASS, SERVER },
212 {2, CMD_UNLOCK, 1, 5, PASS, SERVER },
213 {2, CMD_UNLOCK, 70, 5, PASS, SERVER },
215 /* Add a lock to the middle of a list - no overlap */
216 {3, CMD_WRLOCK, 10, 10, PASS, SERVER },
217 {3, CMD_WRLOCK, 30, 10, PASS, SERVER },
218 {3, CMD_WRLOCK, 50, 10, PASS, SERVER },
219 {3, CMD_WRLOCK, 42, 5, PASS, SERVER },
221 {3, CMD_UNLOCK, 10, 10, PASS, SERVER },
222 {3, CMD_UNLOCK, 30, 10, PASS, SERVER },
223 {3, CMD_UNLOCK, 50, 10, PASS, SERVER },
224 {3, CMD_UNLOCK, 42, 5, PASS, SERVER },
226 /* Add different lock types to middle of the list - overlap exact match - 3 */
227 {4, CMD_WRLOCK, 10, 10, PASS, SERVER },
228 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
229 {4, CMD_WRLOCK, 50, 10, PASS, SERVER },
230 /* Exact match - same lock type */
231 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
232 /* Exact match - different lock type */
233 {4, CMD_RDLOCK, 30, 10, PASS, SERVER },
234 /* Exact match - unlock */
235 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
236 /* New lock - as above, inserting in the list again */
237 {4, CMD_WRLOCK, 30, 10, PASS, SERVER },
239 {4, CMD_UNLOCK, 10, 10, PASS, SERVER },
240 {4, CMD_UNLOCK, 30, 10, PASS, SERVER },
241 {4, CMD_UNLOCK, 50, 10, PASS, SERVER },
243 /* Add new lock which completely overlaps any old lock in the list - 4,5,6 */
244 {5, CMD_WRLOCK, 10, 10, PASS, SERVER },
245 {5, CMD_WRLOCK, 30, 10, PASS, SERVER },
246 {5, CMD_WRLOCK, 50, 10, PASS, SERVER },
247 /* The start is the same, end overlaps */
248 {5, CMD_WRLOCK, 30, 15, PASS, SERVER },
249 /* The start is before, end is the same */
250 {5, CMD_WRLOCK, 25, 20, PASS, SERVER },
251 /* Both start and end overlap */
252 {5, CMD_WRLOCK, 22, 26, PASS, SERVER },
254 {5, CMD_UNLOCK, 10, 10, PASS, SERVER },
255 {5, CMD_UNLOCK, 22, 26, PASS, SERVER },
256 {5, CMD_UNLOCK, 50, 10, PASS, SERVER },
258 /* Add new lock which itself is completely overlaped by any old lock in the list - 7,8,10 */
259 {6, CMD_WRLOCK, 10, 10, PASS, SERVER },
260 {6, CMD_WRLOCK, 30, 10, PASS, SERVER },
261 {6, CMD_WRLOCK, 50, 10, PASS, SERVER },
262 /* The start is the same, end is in the middle of old lock - NOP */
263 {6, CMD_WRLOCK, 30, 5, PASS, SERVER },
264 /* The start and end are in the middle of old lock - NOP */
265 {6, CMD_WRLOCK, 32, 6, PASS, SERVER },
266 /* Start in the middle and end is the same - NOP */
267 {6, CMD_WRLOCK, 32, 8, PASS, SERVER },
269 {6, CMD_UNLOCK, 10, 10, PASS, SERVER },
270 {6, CMD_UNLOCK, 30, 10, PASS, SERVER },
271 {6, CMD_UNLOCK, 32, 8, PASS, SERVER },
272 {6, CMD_UNLOCK, 50, 10, PASS, SERVER },
274 /* Add new lock which starts before any old lock in the list - 2,9 */
275 {7, CMD_WRLOCK, 10, 10, PASS, SERVER },
276 {7, CMD_WRLOCK, 30, 10, PASS, SERVER },
277 {7, CMD_WRLOCK, 50, 10, PASS, SERVER },
278 /* Here is the new lock */
279 {7, CMD_WRLOCK, 27, 10, PASS, SERVER },
280 /* Go again with the end of the new lock matching the start of old lock */
281 {7, CMD_WRLOCK, 25, 2, PASS, SERVER },
283 {7, CMD_UNLOCK, 10, 10, PASS, SERVER },
284 {7, CMD_UNLOCK, 25, 15, PASS, SERVER },
285 {7, CMD_UNLOCK, 50, 10, PASS, SERVER },
287 /* Add new lock which starts in the middle of any old lock in the list and ends after - 11,12 */
288 {8, CMD_WRLOCK, 10, 10, PASS, SERVER },
289 {8, CMD_WRLOCK, 30, 10, PASS, SERVER },
290 {8, CMD_WRLOCK, 50, 10, PASS, SERVER },
291 /* Here is the new lock */
292 {8, CMD_WRLOCK, 35, 10, PASS, SERVER },
293 /* Go again with the end of the new lock matching the start of old lock */
294 {8, CMD_WRLOCK, 45, 2, PASS, SERVER },
296 {8, CMD_UNLOCK, 10, 10, PASS, SERVER },
297 {8, CMD_UNLOCK, 30, 17, PASS, SERVER },
298 {8, CMD_UNLOCK, 50, 10, PASS, SERVER },
299 /* SECTION 2: Overlapping READ and WRITE and CMD_UNLOCK with the same process (SERVER) */
300 /* Add different new lock types which completely overlaps any old lock in the list - 4,5,6 */
301 {9, CMD_WRLOCK, 10, 10, PASS, SERVER },
302 {9, CMD_WRLOCK, 30, 10, PASS, SERVER },
303 {9, CMD_WRLOCK, 50, 10, PASS, SERVER },
304 /* The start is the same, end overlaps */
305 {9, CMD_RDLOCK, 30, 15, PASS, SERVER },
306 /* The start is before, end is the same */
307 {9, CMD_WRLOCK, 25, 20, PASS, SERVER },
308 /* Both start and end overlap */
309 {9, CMD_RDLOCK, 22, 26, PASS, SERVER },
311 {9, CMD_UNLOCK, 10, 10, PASS, SERVER },
312 {9, CMD_UNLOCK, 22, 26, PASS, SERVER },
313 {9, CMD_UNLOCK, 50, 10, PASS, SERVER },
315 /* Add different new locks which are completely overlaped by an old lock in the list - 7,8,10 */
316 {10, CMD_WRLOCK, 10, 10, PASS, SERVER },
317 {10, CMD_WRLOCK, 30, 10, PASS, SERVER },
318 {10, CMD_WRLOCK, 50, 10, PASS, SERVER },
319 /* The start is the same, end is in the middle of old lock */
320 {10, CMD_RDLOCK, 30, 5, PASS, SERVER },
321 /* The start and end are in the middle of a lock */
322 {10, CMD_WRLOCK, 32, 2, PASS, SERVER },
323 /* Start in the middle and end is the same */
324 {10, CMD_RDLOCK, 36, 5, PASS, SERVER },
326 {10, CMD_UNLOCK, 10, 10, PASS, SERVER },
327 {10, CMD_UNLOCK, 30, 11, PASS, SERVER },
328 {10, CMD_UNLOCK, 50, 10, PASS, SERVER },
330 /* Add different new lock types which start before the old lock in the list - 2,9 */
331 {11, CMD_WRLOCK, 10, 10, PASS, SERVER },
332 {11, CMD_WRLOCK, 30, 10, PASS, SERVER },
333 {11, CMD_WRLOCK, 50, 10, PASS, SERVER },
334 /* Here is the new lock */
335 {11, CMD_RDLOCK, 27, 10, PASS, SERVER },
336 /* Go again with the end of the new lock matching the start of lock */
337 {11, CMD_WRLOCK, 25, 3, PASS, SERVER },
339 {11, CMD_UNLOCK, 10, 10, PASS, SERVER },
340 {11, CMD_UNLOCK, 25, 15, PASS, SERVER },
341 {11, CMD_UNLOCK, 50, 10, PASS, SERVER },
343 /* Add different new lock types which start in the middle of an old lock in the list and end after - 11,12 */
344 {12, CMD_WRLOCK, 10, 10, PASS, SERVER },
345 {12, CMD_WRLOCK, 30, 10, PASS, SERVER },
346 {12, CMD_WRLOCK, 50, 10, PASS, SERVER },
347 /* Here is the new lock */
348 {12, CMD_RDLOCK, 35, 10, PASS, SERVER },
349 /* Go again with the end of the new lock matching the start of old lock */
350 {12, CMD_WRLOCK, 44, 3, PASS, SERVER },
352 {12, CMD_UNLOCK, 10, 10, PASS, SERVER },
353 {12, CMD_UNLOCK, 30, 18, PASS, SERVER },
354 {12, CMD_UNLOCK, 50, 10, PASS, SERVER },
356 /* SECTION 3: Overlapping READ and WRITE and CMD_UNLOCK with the different processes (CLIENT/SERVER) */
357 /* Add new lock, differing types and processes, to middle of the list - exact overlap match - 3 */
358 {13, CMD_WRLOCK, 10, 10, PASS, SERVER },
359 {13, CMD_WRLOCK, 30, 10, PASS, SERVER },
360 {13, CMD_RDLOCK, 50, 10, PASS, SERVER },
361 /* Same lock type, different process */
362 {13, CMD_WRLOCK, 30, 10, FAIL, CLIENT },
363 {13, CMD_RDLOCK, 50, 10, PASS, CLIENT },
364 /* Exact match - different lock type, different process */
365 {13, CMD_RDLOCK, 30, 10, FAIL, CLIENT },
366 /* Exact match - unlock */
367 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
368 /* New lock - as above, inserting in the list again */
369 {13, CMD_UNLOCK, 30, 10, PASS, SERVER },
370 /* Exact match - same lock type, different process */
371 {13, CMD_WRLOCK, 30, 10, PASS, CLIENT },
373 {13, CMD_UNLOCK, 10, 10, PASS, SERVER },
374 {13, CMD_UNLOCK, 30, 10, PASS, CLIENT },
375 {13, CMD_UNLOCK, 50, 10, PASS, SERVER },
377 /* Add new lock, differing types and processes, which completely overlap any of the locks in the list - 4,5,6 */
378 {14, CMD_WRLOCK, 10, 10, PASS, SERVER },
379 {14, CMD_WRLOCK, 30, 10, PASS, SERVER },
380 {14, CMD_RDLOCK, 50, 10, PASS, SERVER },
381 /* The start is the same, end overlaps */
382 {14, CMD_RDLOCK, 30, 15, FAIL, CLIENT },
383 {14, CMD_WRLOCK, 30, 15, FAIL, CLIENT },
384 /* The start is before, end is the same */
385 {14, CMD_RDLOCK, 25, 20, FAIL, CLIENT },
386 {14, CMD_WRLOCK, 25, 20, FAIL, CLIENT },
387 /* Both start and end overlap */
388 {14, CMD_RDLOCK, 22, 26, FAIL, CLIENT },
389 {14, CMD_WRLOCK, 22, 26, FAIL, CLIENT },
391 /* The start is the same, end overlaps */
392 {14, CMD_RDLOCK, 50, 15, PASS, CLIENT },
393 {14, CMD_WRLOCK, 50, 17, FAIL, CLIENT },
394 /* The start is before, end is the same */
395 {14, CMD_RDLOCK, 45, 20, PASS, CLIENT },
396 {14, CMD_WRLOCK, 43, 22, FAIL, CLIENT },
397 /* Both start and end overlap */
398 {14, CMD_RDLOCK, 42, 26, PASS, CLIENT },
399 {14, CMD_WRLOCK, 41, 28, FAIL, CLIENT },
401 {14, CMD_UNLOCK, 10, 10, PASS, SERVER },
402 {14, CMD_UNLOCK, 22, 26, PASS, SERVER },
403 {14, CMD_UNLOCK, 42, 26, PASS, CLIENT },
405 /* Add new lock, differing types and processes, which are completely overlaped by an old lock in the list - 7,8,10 */
406 {15, CMD_WRLOCK, 10, 10, PASS, SERVER },
407 {15, CMD_RDLOCK, 30, 10, PASS, SERVER },
408 {15, CMD_WRLOCK, 50, 10, PASS, SERVER },
409 /* The start is the same, end is in the middle of old lock */
410 {15, CMD_RDLOCK, 50, 5, FAIL, CLIENT },
411 {15, CMD_WRLOCK, 50, 5, FAIL, CLIENT },
412 /* The start and end are in the middle of old lock */
413 {15, CMD_RDLOCK, 52, 6, FAIL, CLIENT },
414 {15, CMD_WRLOCK, 52, 6, FAIL, CLIENT },
415 /* Start in the middle and end is the same */
416 {15, CMD_RDLOCK, 52, 8, FAIL, CLIENT },
417 {15, CMD_WRLOCK, 52, 8, FAIL, CLIENT },
418 /* The start is the same, end is in the middle of old lock */
419 {15, CMD_RDLOCK, 30, 5, PASS, CLIENT },
420 {15, CMD_WRLOCK, 30, 5, FAIL, CLIENT },
421 /* The start and end are in the middle of old lock */
422 {15, CMD_RDLOCK, 32, 6, PASS, CLIENT },
423 {15, CMD_WRLOCK, 32, 6, FAIL, CLIENT },
424 /* Start in the middle and end is the same */
425 {15, CMD_RDLOCK, 32, 8, PASS, CLIENT },
426 {15, CMD_WRLOCK, 32, 8, FAIL, CLIENT },
428 {15, CMD_UNLOCK, 10, 10, PASS, SERVER },
429 {15, CMD_UNLOCK, 30, 10, PASS, SERVER },
430 {15, CMD_UNLOCK, 50, 10, PASS, SERVER },
431 /* Add new lock, differing types and processes, which start before a lock in the list - 2,9 */
432 {16, CMD_RDLOCK, 10, 10, PASS, SERVER },
433 {16, CMD_WRLOCK, 50, 10, PASS, SERVER },
434 /* Start is before, end is the start of the old lock in list */
435 {16, CMD_RDLOCK, 5, 6, PASS, CLIENT },
436 {16, CMD_WRLOCK, 5, 6, FAIL, CLIENT },
437 /* Start is before, end is in the middle of the old lock */
438 {16, CMD_RDLOCK, 5, 10, PASS, CLIENT },
439 {16, CMD_WRLOCK, 5, 10, FAIL, CLIENT },
440 /* Start is before, end is the start of the old lock in list */
441 {16, CMD_RDLOCK, 45, 6, FAIL, CLIENT },
442 {16, CMD_WRLOCK, 45, 6, FAIL, CLIENT },
443 /* Start is before, end is in the middle of the old lock */
444 {16, CMD_RDLOCK, 45, 10, FAIL, CLIENT },
445 {16, CMD_WRLOCK, 45, 10, FAIL, CLIENT },
447 {16, CMD_UNLOCK, 5, 15, PASS, CLIENT },
448 {16, CMD_UNLOCK, 30, 10, PASS, SERVER },
449 {16, CMD_UNLOCK, 50, 10, PASS, SERVER },
451 /* Add new lock, differing types and processes, which starts in the middle of a lock, and ends after - 11,12 */
452 {17, CMD_WRLOCK, 10, 10, PASS, SERVER },
453 {17, CMD_RDLOCK, 30, 10, PASS, SERVER },
454 {17, CMD_WRLOCK, 50, 10, PASS, SERVER },
455 /* Start in the middle, end after lock in list */
456 {17, CMD_WRLOCK, 35, 10, FAIL, CLIENT },
457 /* Start matches end of lock in list */
458 {17, CMD_RDLOCK, 35, 10, PASS, CLIENT },
459 {17, CMD_RDLOCK, 44, 2, PASS, CLIENT },
460 /* Start in the middle, end after lock in list */
461 {17, CMD_RDLOCK, 55, 10, FAIL, CLIENT },
462 {17, CMD_WRLOCK, 55, 10, FAIL, CLIENT },
463 /* Start matches end of lock in list */
464 {17, CMD_RDLOCK, 59, 5, FAIL, CLIENT },
465 {17, CMD_WRLOCK, 59, 5, FAIL, CLIENT },
467 {17, CMD_UNLOCK, 10, 10, PASS, SERVER },
468 {17, CMD_UNLOCK, 30, 16, PASS, CLIENT },
469 {17, CMD_UNLOCK, 50, 10, PASS, SERVER },
471 /* SECTION 4: overlapping and EOF tests */
472 /* Acquire overlapping ranges */
473 {18, CMD_WRLOCK, 11, 7, PASS, SERVER },
474 {18, CMD_WRLOCK, 13, 8, FAIL, CLIENT },
475 {18, CMD_UNLOCK, 11, 7, PASS, SERVER },
476 /* Acquire different ranges beyond EOF */
477 {19, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER },
478 {19, CMD_WRLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
479 {19, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER },
480 {19, CMD_UNLOCK, FILE_SIZE + 10, 10, PASS, CLIENT },
481 /* Acquire same range beyong EOF */
482 {20, CMD_WRLOCK, 10, FILE_SIZE, PASS, SERVER, },
483 {20, CMD_WRLOCK, 10, FILE_SIZE, FAIL, CLIENT, },
484 {20, CMD_UNLOCK, 10, FILE_SIZE, PASS, SERVER, },
485 /* Acquire whole file lock */
486 {21, CMD_WRLOCK, 0, 0, PASS, SERVER, },
487 {21, CMD_WRLOCK, 0, 0, FAIL, CLIENT, },
488 {21, CMD_UNLOCK, 0, 0, PASS, SERVER, },
489 /* Acquire whole file lock, then range */
490 {22, CMD_WRLOCK, 0, 0, PASS, SERVER, },
491 {22, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
492 {22, CMD_UNLOCK, 0, 0, PASS, SERVER, },
493 /* Acquire non-overlapping read locks */
494 {23, CMD_RDLOCK, 1, 5, PASS, SERVER, },
495 {23, CMD_RDLOCK, 7, 6, PASS, CLIENT, },
496 {23, CMD_UNLOCK, 1, 5, PASS, SERVER, },
497 {23, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
498 /* Acquire overlapping read locks */
499 {24, CMD_RDLOCK, 1, 5, PASS, SERVER, },
500 {24, CMD_RDLOCK, 2, 6, PASS, CLIENT, },
501 {24, CMD_UNLOCK, 1, 5, PASS, SERVER, },
502 {24, CMD_UNLOCK, 1, 7, PASS, CLIENT, },
503 /* Acquire non-overlapping read and write locks */
504 {25, CMD_RDLOCK, 1, 5, PASS, SERVER, },
505 {25, CMD_WRLOCK, 7, 6, PASS, CLIENT, },
506 {25, CMD_UNLOCK, 1, 5, PASS, SERVER, },
507 {25, CMD_UNLOCK, 7, 6, PASS, CLIENT, },
508 /* Acquire overlapping read and write locks */
509 {26, CMD_RDLOCK, 1, 5, PASS, SERVER, },
510 {26, CMD_WRLOCK, 2, 6, FAIL, CLIENT, },
511 {26, CMD_UNLOCK, 1, 5, PASS, SERVER, },
512 /* Acquire whole file lock, then close (without unlocking) */
513 {27, CMD_WRLOCK, 0, 0, PASS, SERVER, },
514 {27, CMD_WRLOCK, 1, 5, FAIL, CLIENT, },
515 {27, CMD_CLOSE,0, 0, PASS, SERVER, },
516 {27, CMD_WRLOCK, 1, 5, PASS, CLIENT, },
517 {27, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
518 {27, CMD_UNLOCK, 1, 5, PASS, CLIENT, },
519 /* Acquire two read locks, close one file and then reopen to check that first lock still exists */
520 {28, CMD_RDLOCK, 1, 5, PASS, SERVER, },
521 {28, CMD_RDLOCK, 1, 5, PASS, CLIENT, },
522 {28, CMD_CLOSE,0, 0, PASS, SERVER, },
523 {28, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
524 {28, CMD_WRLOCK, 0, 0, FAIL, SERVER, },
525 {28, CMD_UNLOCK, 1, 5, PASS, SERVER, },
526 /* Verify that F_GETLK for F_WRLCK doesn't require that file be opened for write */
527 {29, CMD_CLOSE, 0, 0, PASS, SERVER, },
528 {29, CMD_OPEN, O_RDONLY, 0, PASS, SERVER, },
529 {29, CMD_WRTEST, 0, 0, PASS, SERVER, },
530 {29, CMD_CLOSE,0, 0, PASS, SERVER, },
531 {29, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
533 /* Close the opened file and open the file with SHLOCK, other client will try to open with SHLOCK too */
534 {30, CMD_CLOSE,0, 0, PASS, SERVER, },
535 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
536 {30, CMD_CLOSE,0, 0, PASS, CLIENT, },
537 {30, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, CLIENT, },
538 /* Close the opened file and open the file with SHLOCK, other client will try to open with EXLOCK */
539 {31, CMD_CLOSE,0, 0, PASS, SERVER, },
540 {31, CMD_CLOSE,0, 0, PASS, CLIENT, },
541 {31, CMD_OPEN, O_RDWR|O_SHLOCK|O_NONBLOCK, 0, PASS, SERVER, },
542 {31, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
543 /* Close the opened file and open the file with EXLOCK, other client will try to open with EXLOCK too */
544 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
545 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
546 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, PASS, SERVER, },
547 {32, CMD_OPEN, O_RDWR|O_EXLOCK|O_NONBLOCK, 0, FAIL, CLIENT, },
548 {32, CMD_CLOSE,0, 0, PASS, SERVER, },
549 {32, CMD_CLOSE,0, 0, FAIL, CLIENT, },
550 {32, CMD_OPEN, O_RDWR, 0, PASS, SERVER, },
551 {32, CMD_OPEN, O_RDWR, 0, PASS, CLIENT, },
554 /* indicate end of array */
560 char *lease_descriptions[] = {
561 /* 1 */"Take Read Lease",
562 /* 2 */"Take Write Lease",
563 /* 3 */"Fail Write Lease if file is open somewhere else",
564 /* 4 */"Fail Read Lease if opened with write permissions",
567 static int64_t lease_tests[][6] =
568 /* test # Action [offset|flags|arg] length expected server/client */
570 /* Various tests to exercise leases */
572 /* SECTION 1: Simple verification of being able to take leases */
573 /* Take Read Lease */
574 {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
575 {1, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
576 {1, CMD_CLOSE, 0, 0, PASS, SERVER },
577 {1, CMD_OPEN, O_RDONLY, 0, PASS, SERVER },
578 {1, CMD_SETLEASE, F_RDLCK, 0, PASS, SERVER },
579 {1, CMD_GETLEASE, F_RDLCK, 0, PASS, SERVER },
580 {1, CMD_SETLEASE, F_UNLCK, 0, PASS, SERVER },
581 {1, CMD_CLOSE, 0, 0, PASS, SERVER },
582 {1, CMD_CLOSE, 0, 0, PASS, CLIENT },
584 /* Take Write Lease */
585 {2, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
586 {2, CMD_SETLEASE, F_WRLCK, 0, PASS, SERVER },
587 {2, CMD_GETLEASE, F_WRLCK, 0, PASS, SERVER },
588 {2, CMD_SETLEASE, F_UNLCK, 0, PASS, SERVER },
589 {2, CMD_CLOSE, 0, 0, PASS, SERVER },
590 /* Fail Write Lease with other users */
591 {3, CMD_OPEN, O_RDONLY, 0, PASS, CLIENT },
592 {3, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
593 {3, CMD_SETLEASE, F_WRLCK, 0, FAIL, SERVER },
594 {3, CMD_GETLEASE, F_WRLCK, 0, FAIL, SERVER },
595 {3, CMD_CLOSE, 0, 0, PASS, SERVER },
596 {3, CMD_CLOSE, 0, 0, PASS, CLIENT },
597 /* Fail Read Lease if opened for write */
598 {4, CMD_OPEN, O_RDWR, 0, PASS, SERVER },
599 {4, CMD_SETLEASE, F_RDLCK, 0, FAIL, SERVER },
600 {4, CMD_GETLEASE, F_RDLCK, 0, FAIL, SERVER },
601 {4, CMD_CLOSE, 0, 0, PASS, SERVER },
603 /* indicate end of array */
616 int32_t padding; /* So mac and irix have the same size struct (bloody alignment) */
623 fprintf(stderr, "Usage: %s [options] sharedfile\n\
626 -p port TCP/IP port number for client-server communication\n\
627 -d enable debug tracing\n\
628 -n # test number to run\n\
629 -h host run as client and connect to server on remote host\n\
630 [default run as server]\n", prog);
634 #define INIT_BUFSZ 512
637 initialize(HANDLE fd)
643 int togo = FILE_SIZE;
645 ibuf = (char*)malloc(INIT_BUFSZ);
646 memset(ibuf, ':', INIT_BUFSZ);
651 j = togo > INIT_BUFSZ ? INIT_BUFSZ : togo;
653 if ((nwrite = WRITE(fd, ibuf, j)) != j) {
655 perror("initialize write:");
657 fprintf(stderr, "initialize: write() returns %d, not %d as expected\n",
667 int do_open(int flag)
669 int flags = flag|O_CREAT|O_BINARY;
672 fprintf(stderr, "do_open %s 0x%x\n", filename, flags);
674 if ((f_fd = open(filename, flags, 0666)) == INVALID_HANDLE) {
675 perror("shared file create");
682 static int do_lock(int cmd, int type, int start, int length)
689 fprintf(stderr, "do_lock: cmd=%d type=%d start=%d, length=%d\n", cmd, type, start, length);
697 fl.l_whence = SEEK_SET;
703 ret = fcntl(filedes, cmd, &fl);
707 fprintf(stderr, "do_lock: ret = %d, errno = %d (%s)\n", ret, errno, strerror(errno));
709 return(ret==0?PASS:FAIL);
712 static int do_lease(int cmd, int arg, int expected)
717 fprintf(stderr, "do_lease: cmd=%d arg=%d exp=%X\n",
725 ret = fcntl(f_fd, cmd, arg);
728 if (expected && (expected == ret))
732 fprintf(stderr, "%s do_lease: ret = %d, errno = %d (%s)\n",
733 __FILE__, ret, errno, strerror(errno));
735 return(ret==0?PASS:FAIL);
741 fprintf(stderr, "do_close\n");
746 f_fd = INVALID_HANDLE;
751 fprintf(stderr, "%s errno = %d (%s)\n",
752 __FILE__, errno, strerror(errno));
758 static void init_ctl(int64_t tests[][6], int32_t index)
760 ctl.test= (int32_t)tests[index][TEST_NUM];
761 ctl.command = (int32_t)tests[index][COMMAND];
762 ctl.offset = tests[index][OFFSET];
763 ctl.length = tests[index][LENGTH];
765 ctl.result = (int32_t)tests[index][RESULT];
775 fprintf(stderr, "send_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
776 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length,ctl.result, ctl.error);
779 ctl.test= bswap_uint32(ctl.test);
780 ctl.command = bswap_uint32(ctl.command);
781 ctl.offset = bswap_uint64(ctl.offset);
782 ctl.length = bswap_uint64(ctl.length);
783 ctl.result = bswap_uint32(ctl.result);
784 ctl.index= bswap_uint32(ctl.index);
785 ctl.error = bswap_uint32(ctl.error);
786 nwrite = SOCKET_WRITE(c_fd, (char*)&ctl, sizeof(ctl));
788 ctl.test= bswap_uint32(ctl.test);
789 ctl.command = bswap_uint32(ctl.command);
790 ctl.offset = bswap_uint64(ctl.offset);
791 ctl.length = bswap_uint64(ctl.length);
792 ctl.result = bswap_uint32(ctl.result);
793 ctl.index= bswap_uint32(ctl.index);
794 ctl.error= bswap_uint32(ctl.error);
795 if (nwrite != sizeof(ctl)) {
797 perror("send_ctl: write");
799 fprintf(stderr, "send_ctl[%d]: write() returns %d, not %zu as expected\n",
800 ctl.test, nwrite, sizeof(ctl));
810 if ((nread = SOCKET_READ(c_fd, (char*)&ctl, sizeof(ctl))) != sizeof(ctl)) {
812 perror("recv_ctl: read");
814 fprintf(stderr, "recv_ctl[%d]: read() returns %d, not %zu as expected\n",
815 ctl.test, nread, sizeof(ctl));
816 fprintf(stderr, "socket might has been closed by other locktest\n");
821 ctl.test= bswap_uint32(ctl.test);
822 ctl.command = bswap_uint32(ctl.command);
823 ctl.offset = bswap_uint64(ctl.offset);
824 ctl.length = bswap_uint64(ctl.length);
825 ctl.result = bswap_uint32(ctl.result);
826 ctl.index= bswap_uint32(ctl.index);
827 ctl.error= bswap_uint32(ctl.error);
830 fprintf(stderr, "recv_ctl: test=%d, command=%d offset=%"LL"d, length=%"LL"d, result=%d, error=%d\n",
831 ctl.test, ctl.command, (long long)ctl.offset, (long long)ctl.length, ctl.result, ctl.error);
851 run(int64_t tests[][6], char *descriptions[]);
854 main(int argc, char *argv[])
858 struct sockaddr_in myAddr;
859 struct linger noLinger = {1, 0};
873 /* trim command name of leading directory components */
875 for (p = prog; *p; p++) {
880 while ((c = getopt(argc, argv, "dLn:h:p:?")) != EOF) {
883 case 'd': /* debug flag */
887 case 'L': /* Lease testing */
891 case 'h': /* (server) hostname */
897 testnumber = atoi(optarg);
900 case 'p': /* TCP/IP port */
901 port = (int)strtol(optarg, &endnum, 10);
902 if (*endnum != '\0') {
903 fprintf(stderr, "%s: -p argument must be a numeric\n",
917 if (errflag || optind != argc-1) {
922 filename=argv[optind];
924 fprintf(stderr, "Working on file : %s\n", filename);
925 if (do_open(O_RDWR) == FAIL)
928 setbuf(stderr, NULL);
933 s_fd = socket(AF_INET, SOCK_STREAM, 0);
934 if (s_fd == INVALID_SOCKET) {
939 if (setsockopt(s_fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof(one)) < 0) {
940 perror("setsockopt(nodelay)");
944 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEADDR, (char*)&one, sizeof(one))<0) {
945 perror("setsockopt(reuseaddr)");
950 if (setsockopt(s_fd, SOL_SOCKET, SO_REUSEPORT, (char*)&one, sizeof(one))<0) {
951 perror("setsockopt(reuseport)");
957 memset(&myAddr, 0, sizeof(myAddr));
958 myAddr.sin_family = AF_INET;
959 myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
960 myAddr.sin_port = htons((short)port);
961 sts = bind(s_fd, (struct sockaddr*)&myAddr, sizeof(myAddr));
968 sts = listen(s_fd, 5); /* Max. of 5 pending connection requests */
976 socklen_t addr_len = sizeof(myAddr);
978 if (getsockname(s_fd, &myAddr, &addr_len)) {
979 perror("getsockname");
983 port = ntohs(myAddr.sin_port);
986 printf("server port: %d\n", port);
989 c_fd = accept(s_fd, NULL, NULL);
990 if (c_fd == INVALID_SOCKET) {
996 if (debug) fprintf(stderr, "Client accepted\n");
1000 struct hostent *servInfo;
1002 if ((servInfo = gethostbyname(host)) == NULL) {
1003 fprintf(stderr, "Couldn't get hostbyname for %s", host);
1004 if (h_errno == HOST_NOT_FOUND)
1005 fprintf(stderr, ": host not found");
1006 fprintf(stderr, "\n");
1011 c_fd = socket(AF_INET, SOCK_STREAM, 0);
1012 if (c_fd == INVALID_SOCKET) {
1017 /* avoid 200 ms delay */
1018 if (setsockopt(c_fd, IPPROTO_TCP, TCP_NODELAY, (char *)&i, sizeof(i)) < 0) {
1019 perror("setsockopt(nodelay)");
1023 /* Don't linger on close */
1024 if (setsockopt(c_fd, SOL_SOCKET, SO_LINGER, (char *)&noLinger, sizeof(noLinger)) < 0) {
1025 perror("setsockopt(nolinger)");
1030 memset(&myAddr, 0, sizeof(myAddr)); /* Arrgh! &myAddr, not myAddr */
1031 myAddr.sin_family = AF_INET;
1032 memcpy(&myAddr.sin_addr, servInfo->h_addr, servInfo->h_length);
1033 myAddr.sin_port = htons((short)port);
1035 if (connect(c_fd, (struct sockaddr*)&myAddr, sizeof(myAddr)) < 0) {
1036 perror("unable to connect");
1037 fprintf(stderr, "Server might still initializing the shared file\n ");
1042 if (debug) fprintf(stderr, "Connected to server\n");
1047 /* only server need do shared file */
1051 * TCP/IP connection to be established, safe to proceed.
1053 * real work is in here ...
1056 fail_count = run(lease_tests, lease_descriptions);
1058 fail_count = run(lock_tests, lock_descriptions);
1064 int run(int64_t tests[][6], char *descriptions[])
1070 int test_count = -1;
1075 if(testnumber > 0) {
1076 last_test = testnumber - 1;
1077 while(tests[index][TEST_NUM] != testnumber && tests[index][TEST_NUM] != 0) {
1081 /* If we have a server command, deal with it */
1082 if(tests[index][WHO] == SERVER) {
1084 fprintf(stderr, "Got a server command (%d)\n", index);
1085 if(tests[index][TEST_NUM] == 0) {
1089 memset(&ctl, 0, sizeof(ctl));
1090 ctl.test = tests[index][TEST_NUM];
1092 if(tests[index][TEST_NUM] != 0) {
1093 switch(tests[index][COMMAND]) {
1095 result = do_lock(F_SETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1098 result = do_lock(F_SETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1101 result = do_lock(F_SETLK, F_UNLCK, tests[index][OFFSET], tests[index][LENGTH]);
1104 result = do_close();
1107 result = do_open(tests[index][FLAGS]);
1110 result = do_lock(F_GETLK, F_WRLCK, tests[index][OFFSET], tests[index][LENGTH]);
1113 result = do_lock(F_GETLK, F_RDLCK, tests[index][OFFSET], tests[index][LENGTH]);
1116 result = do_lease(F_SETLEASE, tests[index][ARG], 0);
1119 result = do_lease(F_GETLEASE, tests[index][ARG], tests[index][ARG]);
1122 if( result != tests[index][RESULT]) {
1124 /* We have a failure */
1125 fprintf(stderr, " ***** Server failure *****\n");
1126 fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1127 ctl.test, get_cmd_str(tests[index][COMMAND]),
1128 (long long)tests[index][OFFSET],
1129 (long long)tests[index][LENGTH],
1130 saved_errno, strerror(saved_errno));
1131 fprintf(stderr, " %d:%s\n",
1132 ctl.test, descriptions[ctl.test - 1]);
1135 /* else send it off to the client */
1136 } else if (tests[index][WHO] == CLIENT) {
1137 if(tests[index][TEST_NUM] == 0) {
1141 /* get the client to do something */
1142 init_ctl(tests, index);
1144 fprintf(stderr, "Sending command to client (%d) - %s - %lld:%lld\n",
1146 get_cmd_str(ctl.command),
1147 (long long)tests[index][OFFSET],
1148 (long long)tests[index][LENGTH]);
1149 /* get the client to do something */
1153 /* Get the clients response */
1155 /* this is the whether the test passed or failed,
1156 * not what the command returned */
1157 if( ctl.result == FAIL ) {
1159 fprintf(stderr, " ***** Client failure *****\n");
1160 fprintf(stderr, " in test %d, while %sing using offset %lld, length %lld - err = %d:%s\n",
1161 ctl.test, get_cmd_str(ctl.command),
1162 (long long)ctl.offset, (long long)ctl.length,
1163 ctl.error, strerror(ctl.error));
1164 fprintf(stderr, " %d:%s\n",
1165 ctl.test, descriptions[ctl.test - 1]);
1170 if(last_test != tests[index][TEST_NUM]) {
1175 last_test = tests[index][TEST_NUM];
1179 } else { /* CLIENT */
1181 fprintf(stderr,"client: waiting...\n");
1182 /* wait for the server to do something */
1185 /* check for a client command */
1187 if (tests[index][WHO] != CLIENT) {
1188 fprintf(stderr, "not a client command index (%d)\n", index);
1197 switch(ctl.command) {
1199 result = do_lock(F_SETLK, F_WRLCK, ctl.offset, ctl.length);
1202 result = do_lock(F_SETLK, F_RDLCK, ctl.offset, ctl.length);
1205 result = do_lock(F_SETLK, F_UNLCK, ctl.offset, ctl.length);
1208 result = do_close();
1211 result = do_open(tests[index][FLAGS]);
1214 result = do_lock(F_GETLK, F_WRLCK, ctl.offset, ctl.length);
1217 result = do_lock(F_GETLK, F_RDLCK, ctl.offset, ctl.length);
1219 /* NOTE offset carries the argument values */
1221 result = do_lease(F_SETLEASE, ctl.offset, 0);
1224 result = do_lease(F_GETLEASE, ctl.offset, ctl.offset);
1227 if( result != ctl.result ) {
1228 fprintf(stderr,"Failure in %d:%s\n",
1229 ctl.test, descriptions[ctl.test - 1]);
1230 fprintf(stderr," Got %d, wanted %d\n",
1231 result, ctl.result);
1233 ctl.error = saved_errno;
1240 fprintf(stderr,"client: sending result to server (%d)\n", ctl.index);
1241 /* Send result to the server */
1243 if(last_test != tests[index][TEST_NUM]) {
1245 last_test = tests[index][TEST_NUM];
1249 fprintf(stderr, "%d tests run, %d failed\n", test_count, fail_count);