Whamcloud - gitweb
LU-15129 tests: sanity-quota_75_dom fix
[fs/lustre-release.git] / lustre / tests / group_lock_test.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22
23 /*
24  * Copyright 2014, 2015 Cray Inc, all rights reserved.
25  * Author: Frank Zago.
26  *
27  * A few portions are extracted from llapi_layout_test.c
28  *
29  * The purpose of this test is to exert the group lock ioctls.
30  *
31  * The program will exit as soon as a non zero error code is returned.
32  */
33
34 #include <stdlib.h>
35 #include <errno.h>
36 #include <getopt.h>
37 #include <fcntl.h>
38 #include <sys/ioctl.h>
39 #include <sys/types.h>
40 #include <sys/wait.h>
41 #include <sys/uio.h>
42 #include <sys/stat.h>
43 #include <time.h>
44 #include <unistd.h>
45 #include <poll.h>
46
47 #include <lustre/lustreapi.h>
48
49 #define ERROR(fmt, ...)                                                 \
50         fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
51                 program_invocation_short_name, __FILE__, __LINE__,      \
52                 __func__, ## __VA_ARGS__);
53
54 #define DIE(fmt, ...)                           \
55         do {                                    \
56                 ERROR(fmt, ## __VA_ARGS__);     \
57                 exit(EXIT_FAILURE);             \
58         } while (0)
59
60 #define ASSERTF(cond, fmt, ...)                                         \
61         do {                                                            \
62                 if (!(cond))                                            \
63                         DIE("assertion '%s' failed: "fmt,               \
64                             #cond, ## __VA_ARGS__);                     \
65         } while (0)
66
67 #define PERFORM(testfn) \
68         do {                                                            \
69                 cleanup();                                              \
70                 fprintf(stderr, "Starting test " #testfn " at %lld\n",  \
71                         (unsigned long long)time(NULL));                \
72                 testfn();                                               \
73                 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
74                         (unsigned long long)time(NULL));                \
75                 cleanup();                                              \
76         } while (0)
77
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";
81
82 static char fsmountdir[PATH_MAX];       /* Lustre mountpoint */
83 static char *lustre_dir;                /* Test directory inside Lustre */
84
85 /* Cleanup our test file. */
86 static void cleanup(void)
87 {
88         unlink(mainpath);
89         rmdir(mainpath);
90 }
91
92 /* Test lock / unlock */
93 static void test10(void)
94 {
95         int rc;
96         int fd;
97         int gid;
98         int i;
99
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));
104
105         /* Valid command first. */
106         gid = 1234;
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));
113
114         /* Again */
115         gid = 768;
116         for (i = 0; i < 1000; i++) {
117                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
118                 ASSERTF(rc == 0,
119                         "cannot lock '%s': %s (loop %d)",
120                         mainpath, strerror(errno), i);
121                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
122                 ASSERTF(rc == 0,
123                         "cannot unlock '%s': %s (loop %d)",
124                         mainpath, strerror(errno), i);
125         }
126
127         /* Lock twice. */
128         gid = 97486;
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));
140
141         /* 0 is an invalid gid */
142         gid = 0;
143         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
144         ASSERTF(rc == -1 && errno == EINVAL, "unexpected lock retval: %s",
145                 strerror(errno));
146
147         /* Lock/unlock with a different gid */
148         gid = 3543;
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);
156         }
157         gid = 3543;
158         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
159         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
160
161         close(fd);
162 }
163
164 /* Test open/lock/close without unlocking */
165 static void test11(void)
166 {
167         int rc;
168         int fd;
169         int gid;
170         char buf[10000];
171
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));
180         close(fd);
181
182         /* Open/lock and close many times. Open with different
183          * flags. */
184         for (gid = 1; gid < 10000; gid++) {
185                 int oflags = O_RDONLY;
186
187                 switch (gid % 10) {
188                 case 0:
189                         oflags = O_RDONLY;
190                         break;
191                 case 1:
192                         oflags = O_WRONLY;
193                         break;
194                 case 2:
195                         oflags = O_WRONLY | O_APPEND;
196                         break;
197                 case 3:
198                         oflags = O_WRONLY | O_CLOEXEC;
199                         break;
200                 case 4:
201                         oflags = O_WRONLY | O_DIRECT;
202                         break;
203                 case 5:
204                         oflags = O_WRONLY | O_NOATIME;
205                         break;
206                 case 6:
207                         oflags = O_WRONLY | O_SYNC;
208                         break;
209                 case 7:
210                         oflags = O_RDONLY | O_DIRECT;
211                         break;
212                 case 8:
213                         oflags = O_RDWR;
214                         break;
215                 case 9:
216                         oflags = O_RDONLY | O_LOV_DELAY_CREATE;
217                         break;
218                 }
219
220                 fd = open(mainpath, oflags);
221                 ASSERTF(fd >= 0, "open failed for '%s': %s (oflags=%d, gid=%d)",
222                         mainpath, strerror(errno), oflags, gid);
223
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);
227
228                 close(fd);
229         }
230 }
231
232 /* Lock / unlock a volatile file, with different creation flags */
233 static void test12(void)
234 {
235         int rc;
236         int fd;
237         int gid;
238
239         rc = mkdir(mainpath, 0600);
240         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
241                 mainpath, strerror(errno));
242
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));
246
247         gid = 34895;
248         rc = llapi_group_lock(fd, gid);
249         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
250
251         rc = llapi_group_unlock(fd, gid);
252         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
253
254         close(fd);
255
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));
260
261         gid = 3354895;
262         rc = llapi_group_lock(fd, gid);
263         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
264
265         rc = llapi_group_unlock(fd, gid);
266         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
267
268         close(fd);
269
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));
273
274         gid = 3489655;
275         rc = llapi_group_lock(fd, gid);
276         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
277
278         rc = llapi_group_unlock(fd, gid);
279         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
280
281         close(fd);
282 }
283
284 static void helper_test20(int fd)
285 {
286         int gid;
287         int rc;
288
289         gid = 1234;
290         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
291         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
292                 rc, strerror(errno));
293
294         gid = 0;
295         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
296         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
297                 rc, strerror(errno));
298
299         gid = 1;
300         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
301         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
302                 rc, strerror(errno));
303
304         gid = -1;
305         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
306         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
307                 rc, strerror(errno));
308 }
309
310 /* Test lock / unlock on a directory */
311 static void test20(void)
312 {
313         int fd;
314         int rc;
315         char dname[PATH_MAX];
316
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));
320         helper_test20(fd);
321         close(fd);
322
323         /* Try .lustre/ . Should fail. */
324         rc = snprintf(dname, sizeof(dname), "%s/.lustre", fsmountdir);
325         ASSERTF(rc < sizeof(dname), "Name too long");
326
327         fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
328         ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
329         helper_test20(fd);
330         close(fd);
331
332         /* A regular directory. */
333         rc = mkdir(mainpath, 0600);
334         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
335                 mainpath, strerror(errno));
336
337         fd = open(mainpath, O_RDONLY | O_DIRECTORY);
338         ASSERTF(fd >= 0, "open failed for '%s': %s",
339                 mainpath, strerror(errno));
340         helper_test20(fd);
341         close(fd);
342 }
343
344 /* Test locking between several fds. */
345 static void test30(void)
346 {
347         int fd1;
348         int fd2;
349         int gid;
350         int gid2;
351         int rc;
352
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));
357
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));
362
363         /* Valid command first. */
364         gid = 1234;
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));
369
370         /* Lock on one fd, unlock on the other */
371         gid = 6947556;
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));
379
380         /* Lock from both */
381         gid = 89489665;
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));
390
391         /* Lock from both. Unlock in reverse order. */
392         gid = 89489665;
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));
401
402         /* Try to lock with different gids */
403         gid = 89489665;
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);
408                 if (gid2 == 0)
409                         ASSERTF(rc == -1 && errno == EINVAL,
410                                 "unexpected lock retval for gid %d: %s",
411                                 gid2, strerror(errno));
412                 else
413                         ASSERTF(rc == -1 && errno == EAGAIN,
414                                 "unexpected lock retval for gid %d: %s",
415                                 gid2, strerror(errno));
416         }
417         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
418         ASSERTF(rc == 0, "cannot unlock '%s': %s",
419                 mainpath, strerror(errno));
420
421         close(fd1);
422         close(fd2);
423 }
424
425 /* Test locking between several fds. */
426 static void test40(void)
427 {
428         int rc;
429         int fd;
430         int gid;
431         char buf[10000];
432         int i, j, threads = 40;
433
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));
439         /* Lock */
440         gid = 1234;
441         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
442         ASSERTF(rc == 0, "cannot lock '%s' gid %d: %s", mainpath, gid,
443                 strerror(errno));
444
445         for (i = 0; i < threads; i++) {
446                 rc = fork();
447                 ASSERTF(rc >= 0, "fork failed %s", strerror(errno));
448
449                 if (rc == 0) {
450                         struct iovec io = { .iov_base = buf,
451                                             .iov_len = sizeof(buf)};
452
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));
458
459                         close(fd);
460                         exit(0);
461                 }
462         }
463
464         while ((i = wait(&rc)) > 0);
465
466         /* Check data */
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",
473                                 j, i, buf[j]);
474         }
475
476         /* close unlock group lock */
477         rc = close(fd);
478         ASSERTF(rc == 0, "close failed '%s': %s",
479                 mainpath, strerror(errno));
480 }
481
482 static void usage(char *prog)
483 {
484         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
485         exit(EXIT_FAILURE);
486 }
487
488 static void process_args(int argc, char *argv[])
489 {
490         int c;
491
492         while ((c = getopt(argc, argv, "d:")) != -1) {
493                 switch (c) {
494                 case 'd':
495                         lustre_dir = optarg;
496                         break;
497                 case '?':
498                 default:
499                         fprintf(stderr, "Unknown option '%c'\n", optopt);
500                         usage(argv[0]);
501                         break;
502                 }
503         }
504 }
505
506 int main(int argc, char *argv[])
507 {
508         char fsname[8 + 1];
509         int rc;
510
511         process_args(argc, argv);
512         if (lustre_dir == NULL)
513                 lustre_dir = "/mnt/lustre";
514
515         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
516         if (rc != 0) {
517                 fprintf(stderr, "Error: '%s': not a Lustre filesystem\n",
518                         lustre_dir);
519                 return EXIT_FAILURE;
520         }
521
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);
525
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");
529         cleanup();
530
531         atexit(cleanup);
532
533         PERFORM(test10);
534         PERFORM(test11);
535         PERFORM(test12);
536         PERFORM(test20);
537         PERFORM(test30);
538         PERFORM(test40);
539
540         return EXIT_SUCCESS;
541 }