4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
24 * Copyright 2014, 2015 Cray Inc, all rights reserved.
27 * A few portions are extracted from llapi_layout_test.c
29 * The purpose of this test is to exert the group lock ioctls.
31 * The program will exit as soon as a non zero error code is returned.
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
47 #include <lustre/lustreapi.h>
49 #define ERROR(fmt, ...) \
50 fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \
51 program_invocation_short_name, __FILE__, __LINE__, \
52 __func__, ## __VA_ARGS__);
54 #define DIE(fmt, ...) \
56 ERROR(fmt, ## __VA_ARGS__); \
60 #define ASSERTF(cond, fmt, ...) \
63 DIE("assertion '%s' failed: "fmt, \
64 #cond, ## __VA_ARGS__); \
67 #define PERFORM(testfn) \
70 fprintf(stderr, "Starting test " #testfn " at %lld\n", \
71 (unsigned long long)time(NULL)); \
73 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
74 (unsigned long long)time(NULL)); \
78 /* Name of file/directory. Will be set once and will not change. */
79 static char mainpath[PATH_MAX];
80 static const char *maindir = "group_lock_test_name_9585766";
82 static char fsmountdir[PATH_MAX]; /* Lustre mountpoint */
83 static char *lustre_dir; /* Test directory inside Lustre */
85 /* Cleanup our test file. */
86 static void cleanup(void)
92 /* Test lock / unlock */
93 static void test10(void)
100 /* Create the test file, and open it. */
101 fd = creat(mainpath, 0);
102 ASSERTF(fd >= 0, "creat failed for '%s': %s",
103 mainpath, strerror(errno));
105 /* Valid command first. */
107 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
108 ASSERTF(rc == 0, "cannot lock '%s': %s",
109 mainpath, strerror(errno));
110 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
111 ASSERTF(rc == 0, "cannot unlock '%s': %s",
112 mainpath, strerror(errno));
116 for (i = 0; i < 1000; i++) {
117 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
119 "cannot lock '%s': %s (loop %d)",
120 mainpath, strerror(errno), i);
121 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
123 "cannot unlock '%s': %s (loop %d)",
124 mainpath, strerror(errno), i);
129 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
130 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
131 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
132 ASSERTF(rc == -1 && errno == EINVAL,
133 "lock unexpectedly granted for '%s': %s",
134 mainpath, strerror(errno));
135 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
136 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
137 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
138 ASSERTF(rc == -1 && errno == EINVAL, "unexpected unlock retval: %d %s",
139 rc, strerror(errno));
141 /* 0 is an invalid gid */
143 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
144 ASSERTF(rc == -1 && errno == EINVAL, "unexpected lock retval: %s",
147 /* Lock/unlock with a different gid */
149 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
150 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
151 for (gid = -10; gid < 10; gid++) {
152 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
153 ASSERTF(rc == -1 && errno == EINVAL,
154 "unexpected unlock retval: %d %s (gid %d)",
155 rc, strerror(errno), gid);
158 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
159 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
164 /* Test open/lock/close without unlocking */
165 static void test11(void)
172 /* Create the test file. */
173 fd = creat(mainpath, 0);
174 ASSERTF(fd >= 0, "creat failed for '%s': %s",
175 mainpath, strerror(errno));
176 memset(buf, 0x5a, sizeof(buf));
177 rc = write(fd, buf, sizeof(buf));
178 ASSERTF(rc == sizeof(buf), "write failed for '%s': %s",
179 mainpath, strerror(errno));
182 /* Open/lock and close many times. Open with different
184 for (gid = 1; gid < 10000; gid++) {
185 int oflags = O_RDONLY;
195 oflags = O_WRONLY | O_APPEND;
198 oflags = O_WRONLY | O_CLOEXEC;
201 oflags = O_WRONLY | O_DIRECT;
204 oflags = O_WRONLY | O_NOATIME;
207 oflags = O_WRONLY | O_SYNC;
210 oflags = O_RDONLY | O_DIRECT;
216 oflags = O_RDONLY | O_LOV_DELAY_CREATE;
220 fd = open(mainpath, oflags);
221 ASSERTF(fd >= 0, "open failed for '%s': %s (oflags=%d, gid=%d)",
222 mainpath, strerror(errno), oflags, gid);
224 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
225 ASSERTF(rc == 0, "cannot lock '%s': %s (oflags=%d, gid=%d)",
226 mainpath, strerror(errno), oflags, gid);
232 /* Lock / unlock a volatile file, with different creation flags */
233 static void test12(void)
239 rc = mkdir(mainpath, 0600);
240 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
241 mainpath, strerror(errno));
243 fd = llapi_create_volatile_idx(mainpath, -1, O_CREAT | O_WRONLY);
244 ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
245 mainpath, strerror(-fd));
248 rc = llapi_group_lock(fd, gid);
249 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
251 rc = llapi_group_unlock(fd, gid);
252 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
256 fd = llapi_create_volatile_idx(mainpath, -1,
257 O_CREAT | O_WRONLY | O_LOV_DELAY_CREATE);
258 ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
259 mainpath, strerror(-fd));
262 rc = llapi_group_lock(fd, gid);
263 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
265 rc = llapi_group_unlock(fd, gid);
266 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
270 fd = llapi_create_volatile_idx(mainpath, -1, O_RDONLY);
271 ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
272 mainpath, strerror(-fd));
275 rc = llapi_group_lock(fd, gid);
276 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
278 rc = llapi_group_unlock(fd, gid);
279 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
284 static void helper_test20(int fd)
290 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
291 ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
292 rc, strerror(errno));
295 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
296 ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
297 rc, strerror(errno));
300 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
301 ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
302 rc, strerror(errno));
305 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
306 ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
307 rc, strerror(errno));
310 /* Test lock / unlock on a directory */
311 static void test20(void)
315 char dname[PATH_MAX];
317 /* Try the mountpoint. Should fail. */
318 fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
319 ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
323 /* Try .lustre/ . Should fail. */
324 rc = snprintf(dname, sizeof(dname), "%s/.lustre", fsmountdir);
325 ASSERTF(rc < sizeof(dname), "Name too long");
327 fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
328 ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
332 /* A regular directory. */
333 rc = mkdir(mainpath, 0600);
334 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
335 mainpath, strerror(errno));
337 fd = open(mainpath, O_RDONLY | O_DIRECTORY);
338 ASSERTF(fd >= 0, "open failed for '%s': %s",
339 mainpath, strerror(errno));
344 /* Test locking between several fds. */
345 static void test30(void)
353 /* Create the test file, and open it. */
354 fd1 = creat(mainpath, 0);
355 ASSERTF(fd1 >= 0, "open failed for '%s': %s",
356 mainpath, strerror(errno));
358 /* Open a second time in non blocking mode. */
359 fd2 = open(mainpath, O_RDWR | O_NONBLOCK);
360 ASSERTF(fd2 >= 0, "open failed for '%s': %s",
361 mainpath, strerror(errno));
363 /* Valid command first. */
365 rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
366 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
367 rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
368 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
370 /* Lock on one fd, unlock on the other */
372 rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
373 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
374 rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
375 ASSERTF(rc == -1 && errno == EINVAL,
376 "unexpected unlock retval: %d %s", rc, strerror(errno));
377 rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
378 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
382 rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
383 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
384 rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
385 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
386 rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
387 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
388 rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
389 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
391 /* Lock from both. Unlock in reverse order. */
393 rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
394 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
395 rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
396 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
397 rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
398 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
399 rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
400 ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
402 /* Try to lock with different gids */
404 rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
405 ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
406 for (gid2 = -50; gid2 < 50; gid2++) {
407 rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid2);
409 ASSERTF(rc == -1 && errno == EINVAL,
410 "unexpected lock retval for gid %d: %s",
411 gid2, strerror(errno));
413 ASSERTF(rc == -1 && errno == EAGAIN,
414 "unexpected lock retval for gid %d: %s",
415 gid2, strerror(errno));
417 rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
418 ASSERTF(rc == 0, "cannot unlock '%s': %s",
419 mainpath, strerror(errno));
425 /* Test locking between several fds. */
426 static void test40(void)
432 int i, j, threads = 40;
434 /* Create the test file. */
435 fd = open(mainpath, O_RDWR | O_CREAT | O_TRUNC,
436 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
437 ASSERTF(fd >= 0, "creat failed for '%s': %s",
438 mainpath, strerror(errno));
441 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
442 ASSERTF(rc == 0, "cannot lock '%s' gid %d: %s", mainpath, gid,
445 for (i = 0; i < threads; i++) {
447 ASSERTF(rc >= 0, "fork failed %s", strerror(errno));
450 struct iovec io = { .iov_base = buf,
451 .iov_len = sizeof(buf)};
453 /* writing to a fixed offset */
454 memset(buf, i, sizeof(buf));
455 rc = pwritev(fd, &io, 1, sizeof(buf) * i);
456 ASSERTF(rc == sizeof(buf), "write failed for '%s' block %d: %s",
457 mainpath, i, strerror(errno));
464 while ((i = wait(&rc)) > 0);
467 for (i = 0; i < threads; i++) {
468 rc = read(fd, buf, sizeof(buf));
469 ASSERTF(rc == sizeof(buf), "read failed for '%s': %s",
470 mainpath, strerror(errno));
471 for (j = 0; j < rc; j++)
472 ASSERTF(i == buf[j], "wrong data at off %d %d != %d",
476 /* close unlock group lock */
478 ASSERTF(rc == 0, "close failed '%s': %s",
479 mainpath, strerror(errno));
482 static void usage(char *prog)
484 fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
488 static void process_args(int argc, char *argv[])
492 while ((c = getopt(argc, argv, "d:")) != -1) {
499 fprintf(stderr, "Unknown option '%c'\n", optopt);
506 int main(int argc, char *argv[])
511 process_args(argc, argv);
512 if (lustre_dir == NULL)
513 lustre_dir = "/mnt/lustre";
515 rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
517 fprintf(stderr, "Error: '%s': not a Lustre filesystem\n",
522 /* Play nice with Lustre test scripts. Non-line buffered output
523 * stream under I/O redirection may appear incorrectly. */
524 setvbuf(stdout, NULL, _IOLBF, 0);
526 /* Create a test filename and reuse it. Remove possibly old files. */
527 rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, maindir);
528 ASSERTF(rc > 0 && rc < sizeof(mainpath), "invalid name for mainpath");