Whamcloud - gitweb
LU-6422 tests: tests group lock on volatiles
[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/types.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <poll.h>
42
43 #include <lustre/lustreapi.h>
44 #include <lustre/lustre_idl.h>
45
46 #define ERROR(fmt, ...)                                                 \
47         fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
48                 program_invocation_short_name, __FILE__, __LINE__,      \
49                 __func__, ## __VA_ARGS__);
50
51 #define DIE(fmt, ...)                           \
52         do {                                    \
53                 ERROR(fmt, ## __VA_ARGS__);     \
54                 exit(EXIT_FAILURE);             \
55         } while (0)
56
57 #define ASSERTF(cond, fmt, ...)                                         \
58         do {                                                            \
59                 if (!(cond))                                            \
60                         DIE("assertion '%s' failed: "fmt,               \
61                             #cond, ## __VA_ARGS__);                     \
62         } while (0)
63
64 #define PERFORM(testfn) \
65         do {                                                            \
66                 cleanup();                                              \
67                 fprintf(stderr, "Starting test " #testfn " at %lld\n",  \
68                         (unsigned long long)time(NULL));                \
69                 testfn();                                               \
70                 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
71                         (unsigned long long)time(NULL));                \
72                 cleanup();                                              \
73         } while (0)
74
75 /* Name of file/directory. Will be set once and will not change. */
76 static char mainpath[PATH_MAX];
77 static const char *maindir = "group_lock_test_name_9585766";
78
79 static char fsmountdir[PATH_MAX];       /* Lustre mountpoint */
80 static char *lustre_dir;                /* Test directory inside Lustre */
81
82 /* Cleanup our test file. */
83 static void cleanup(void)
84 {
85         unlink(mainpath);
86         rmdir(mainpath);
87 }
88
89 /* Test lock / unlock */
90 static void test10(void)
91 {
92         int rc;
93         int fd;
94         int gid;
95         int i;
96
97         /* Create the test file, and open it. */
98         fd = creat(mainpath, 0);
99         ASSERTF(fd >= 0, "creat failed for '%s': %s",
100                 mainpath, strerror(errno));
101
102         /* Valid command first. */
103         gid = 1234;
104         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
105         ASSERTF(rc == 0, "cannot lock '%s': %s",
106                 mainpath, strerror(errno));
107         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
108         ASSERTF(rc == 0, "cannot unlock '%s': %s",
109                 mainpath, strerror(errno));
110
111         /* Again */
112         gid = 768;
113         for (i = 0; i < 1000; i++) {
114                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
115                 ASSERTF(rc == 0,
116                         "cannot lock '%s': %s (loop %d)",
117                         mainpath, strerror(errno), i);
118                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
119                 ASSERTF(rc == 0,
120                         "cannot unlock '%s': %s (loop %d)",
121                         mainpath, strerror(errno), i);
122         }
123
124         /* Lock twice. */
125         gid = 97486;
126         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
127         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
128         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
129         ASSERTF(rc == -1 && errno == EINVAL,
130                 "lock unexpectedly granted for '%s': %s",
131                 mainpath, strerror(errno));
132         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
133         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
134         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
135         ASSERTF(rc == -1 && errno == EINVAL, "unexpected unlock retval: %d %s",
136                 rc, strerror(errno));
137
138         /* 0 is an invalid gid */
139         gid = 0;
140         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
141         ASSERTF(rc == -1 && errno == EINVAL, "unexpected lock retval: %s",
142                 strerror(errno));
143
144         /* Lock/unlock with a different gid */
145         gid = 3543;
146         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
147         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
148         for (gid = -10; gid < 10; gid++) {
149                 rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
150                 ASSERTF(rc == -1 && errno == EINVAL,
151                         "unexpected unlock retval: %d %s (gid %d)",
152                         rc, strerror(errno), gid);
153         }
154         gid = 3543;
155         rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
156         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
157
158         close(fd);
159 }
160
161 /* Test open/lock/close without unlocking */
162 static void test11(void)
163 {
164         int rc;
165         int fd;
166         int gid;
167         char buf[10000];
168
169         /* Create the test file. */
170         fd = creat(mainpath, 0);
171         ASSERTF(fd >= 0, "creat failed for '%s': %s",
172                 mainpath, strerror(errno));
173         memset(buf, 0x5a, sizeof(buf));
174         rc = write(fd, buf, sizeof(buf));
175         ASSERTF(rc == sizeof(buf), "write failed for '%s': %s",
176                 mainpath, strerror(errno));
177         close(fd);
178
179         /* Open/lock and close many times. Open with different
180          * flags. */
181         for (gid = 1; gid < 10000; gid++) {
182                 int oflags = O_RDONLY;
183
184                 switch (gid % 10) {
185                 case 0:
186                         oflags = O_RDONLY;
187                         break;
188                 case 1:
189                         oflags = O_WRONLY;
190                         break;
191                 case 2:
192                         oflags = O_WRONLY | O_APPEND;
193                         break;
194                 case 3:
195                         oflags = O_WRONLY | O_CLOEXEC;
196                         break;
197                 case 4:
198                         oflags = O_WRONLY | O_DIRECT;
199                         break;
200                 case 5:
201                         oflags = O_WRONLY | O_NOATIME;
202                         break;
203                 case 6:
204                         oflags = O_WRONLY | O_SYNC;
205                         break;
206                 case 7:
207                         oflags = O_RDONLY | O_DIRECT;
208                         break;
209                 case 8:
210                         oflags = O_RDWR;
211                         break;
212                 case 9:
213                         oflags = O_RDONLY | O_LOV_DELAY_CREATE;
214                         break;
215                 }
216
217                 fd = open(mainpath, oflags);
218                 ASSERTF(fd >= 0, "open failed for '%s': %s (oflags=%d, gid=%d)",
219                         mainpath, strerror(errno), oflags, gid);
220
221                 rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
222                 ASSERTF(rc == 0, "cannot lock '%s': %s (oflags=%d, gid=%d)",
223                         mainpath, strerror(errno), oflags, gid);
224
225                 close(fd);
226         }
227 }
228
229 /* Lock / unlock a volatile file, with different creation flags */
230 static void test12(void)
231 {
232         int rc;
233         int fd;
234         int gid;
235
236         rc = mkdir(mainpath, 0600);
237         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
238                 mainpath, strerror(errno));
239
240         fd = llapi_create_volatile_idx(mainpath, -1, O_CREAT | O_WRONLY);
241         ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
242                 mainpath, strerror(-fd));
243
244         gid = 34895;
245         rc = llapi_group_lock(fd, gid);
246         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
247
248         rc = llapi_group_unlock(fd, gid);
249         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
250
251         close(fd);
252
253         fd = llapi_create_volatile_idx(mainpath, -1,
254                                        O_CREAT | O_WRONLY | O_LOV_DELAY_CREATE);
255         ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
256                 mainpath, strerror(-fd));
257
258         gid = 3354895;
259         rc = llapi_group_lock(fd, gid);
260         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
261
262         rc = llapi_group_unlock(fd, gid);
263         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
264
265         close(fd);
266
267         fd = llapi_create_volatile_idx(mainpath, -1, O_RDONLY);
268         ASSERTF(fd >= 0, "llapi_create_volatile_idx failed on '%s': %s",
269                 mainpath, strerror(-fd));
270
271         gid = 3489655;
272         rc = llapi_group_lock(fd, gid);
273         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(-rc));
274
275         rc = llapi_group_unlock(fd, gid);
276         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(-rc));
277
278         close(fd);
279 }
280
281 static void helper_test20(int fd)
282 {
283         int gid;
284         int rc;
285
286         gid = 1234;
287         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
288         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
289                 rc, strerror(errno));
290
291         gid = 0;
292         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
293         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
294                 rc, strerror(errno));
295
296         gid = 1;
297         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
298         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
299                 rc, strerror(errno));
300
301         gid = -1;
302         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
303         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
304                 rc, strerror(errno));
305 }
306
307 /* Test lock / unlock on a directory */
308 static void test20(void)
309 {
310         int fd;
311         int rc;
312         char dname[PATH_MAX];
313
314         /* Try the mountpoint. Should fail. */
315         fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
316         ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
317         helper_test20(fd);
318         close(fd);
319
320         /* Try .lustre/ . Should fail. */
321         rc = snprintf(dname, sizeof(dname), "%s/.lustre", fsmountdir);
322         ASSERTF(rc < sizeof(dname), "Name too long");
323
324         fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
325         ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
326         helper_test20(fd);
327         close(fd);
328
329         /* A regular directory. */
330         rc = mkdir(mainpath, 0600);
331         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
332                 mainpath, strerror(errno));
333
334         fd = open(mainpath, O_RDONLY | O_DIRECTORY);
335         ASSERTF(fd >= 0, "open failed for '%s': %s",
336                 mainpath, strerror(errno));
337         helper_test20(fd);
338         close(fd);
339 }
340
341 /* Test locking between several fds. */
342 static void test30(void)
343 {
344         int fd1;
345         int fd2;
346         int gid;
347         int gid2;
348         int rc;
349
350         /* Create the test file, and open it. */
351         fd1 = creat(mainpath, 0);
352         ASSERTF(fd1 >= 0, "open failed for '%s': %s",
353                 mainpath, strerror(errno));
354
355         /* Open a second time in non blocking mode. */
356         fd2 = open(mainpath, O_RDWR | O_NONBLOCK);
357         ASSERTF(fd2 >= 0, "open failed for '%s': %s",
358                 mainpath, strerror(errno));
359
360         /* Valid command first. */
361         gid = 1234;
362         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
363         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
364         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
365         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
366
367         /* Lock on one fd, unlock on the other */
368         gid = 6947556;
369         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
370         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
371         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
372         ASSERTF(rc == -1 && errno == EINVAL,
373                 "unexpected unlock retval: %d %s", rc, strerror(errno));
374         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
375         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
376
377         /* Lock from both */
378         gid = 89489665;
379         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
380         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
381         rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
382         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
383         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
384         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
385         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
386         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
387
388         /* Lock from both. Unlock in reverse order. */
389         gid = 89489665;
390         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
391         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
392         rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
393         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
394         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
395         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
396         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
397         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
398
399         /* Try to lock with different gids */
400         gid = 89489665;
401         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
402         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
403         for (gid2 = -50; gid2 < 50; gid2++) {
404                 rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid2);
405                 if (gid2 == 0)
406                         ASSERTF(rc == -1 && errno == EINVAL,
407                                 "unexpected lock retval for gid %d: %s",
408                                 gid2, strerror(errno));
409                 else
410                         ASSERTF(rc == -1 && errno == EAGAIN,
411                                 "unexpected lock retval for gid %d: %s",
412                                 gid2, strerror(errno));
413         }
414         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
415         ASSERTF(rc == 0, "cannot unlock '%s': %s",
416                 mainpath, strerror(errno));
417
418         close(fd1);
419         close(fd2);
420 }
421
422 static void usage(char *prog)
423 {
424         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
425         exit(EXIT_FAILURE);
426 }
427
428 static void process_args(int argc, char *argv[])
429 {
430         int c;
431
432         while ((c = getopt(argc, argv, "d:")) != -1) {
433                 switch (c) {
434                 case 'd':
435                         lustre_dir = optarg;
436                         break;
437                 case '?':
438                 default:
439                         fprintf(stderr, "Unknown option '%c'\n", optopt);
440                         usage(argv[0]);
441                         break;
442                 }
443         }
444 }
445
446 int main(int argc, char *argv[])
447 {
448         char fsname[8 + 1];
449         int rc;
450
451         process_args(argc, argv);
452         if (lustre_dir == NULL)
453                 lustre_dir = "/mnt/lustre";
454
455         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
456         if (rc != 0) {
457                 fprintf(stderr, "Error: '%s': not a Lustre filesystem\n",
458                         lustre_dir);
459                 return EXIT_FAILURE;
460         }
461
462         /* Play nice with Lustre test scripts. Non-line buffered output
463          * stream under I/O redirection may appear incorrectly. */
464         setvbuf(stdout, NULL, _IOLBF, 0);
465
466         /* Create a test filename and reuse it. Remove possibly old files. */
467         rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, maindir);
468         ASSERTF(rc > 0 && rc < sizeof(mainpath), "invalid name for mainpath");
469         cleanup();
470
471         atexit(cleanup);
472
473         PERFORM(test10);
474         PERFORM(test11);
475         PERFORM(test12);
476         PERFORM(test20);
477         PERFORM(test30);
478
479         return EXIT_SUCCESS;
480 }