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