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