Whamcloud - gitweb
13338df864aab3e8a4e35fc66a138f208a9ddeb4
[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 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                 fprintf(stderr, "Starting test " #testfn " at %lld\n",  \
67                         (unsigned long long)time(NULL));                \
68                 testfn();                                               \
69                 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
70                         (unsigned long long)time(NULL));                \
71         } while (0)
72
73 /* Name of file/directory. Will be set once and will not change. */
74 static char mainpath[PATH_MAX];
75 static const char *maindir = "group_lock_test_name_9585766";
76
77 static char fsmountdir[PATH_MAX];       /* Lustre mountpoint */
78 static char *lustre_dir;                /* Test directory inside Lustre */
79
80 /* Cleanup our test file. */
81 static void cleanup(void)
82 {
83         unlink(mainpath);
84         rmdir(mainpath);
85 }
86
87 /* Test lock / unlock */
88 static void test10(void)
89 {
90         int rc;
91         int fd;
92         int gid;
93         int i;
94
95         cleanup();
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         cleanup();
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         cleanup();
231 }
232
233 static void helper_test20(int fd)
234 {
235         int gid;
236         int rc;
237
238         gid = 1234;
239         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
240         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
241                 rc, strerror(errno));
242
243         gid = 0;
244         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
245         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
246                 rc, strerror(errno));
247
248         gid = 1;
249         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
250         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
251                 rc, strerror(errno));
252
253         gid = -1;
254         rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
255         ASSERTF(rc == -1 && errno == ENOTTY, "unexpected retval: %d %s",
256                 rc, strerror(errno));
257 }
258
259 /* Test lock / unlock on a directory */
260 static void test20(void)
261 {
262         int fd;
263         int rc;
264         char dname[PATH_MAX];
265
266         cleanup();
267
268         /* Try the mountpoint. Should fail. */
269         fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
270         ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
271         helper_test20(fd);
272         close(fd);
273
274         /* Try .lustre/ . Should fail. */
275         rc = snprintf(dname, sizeof(dname), "%s/.lustre", fsmountdir);
276         ASSERTF(rc < sizeof(dname), "Name too long");
277
278         fd = open(fsmountdir, O_RDONLY | O_DIRECTORY);
279         ASSERTF(fd >= 0, "open failed for '%s': %s", mainpath, strerror(errno));
280         helper_test20(fd);
281         close(fd);
282
283         /* A regular directory. */
284         rc = mkdir(mainpath, 0600);
285         ASSERTF(fd >= 0, "mkdir failed for '%s': %s",
286                 mainpath, strerror(errno));
287
288         fd = open(mainpath, O_RDONLY | O_DIRECTORY);
289         ASSERTF(fd >= 0, "open failed for '%s': %s",
290                 mainpath, strerror(errno));
291         helper_test20(fd);
292         close(fd);
293 }
294
295 /* Test locking between several fds. */
296 static void test30(void)
297 {
298         int fd1;
299         int fd2;
300         int gid;
301         int gid2;
302         int rc;
303
304         cleanup();
305
306         /* Create the test file, and open it. */
307         fd1 = creat(mainpath, 0);
308         ASSERTF(fd1 >= 0, "open failed for '%s': %s",
309                 mainpath, strerror(errno));
310
311         /* Open a second time in non blocking mode. */
312         fd2 = open(mainpath, O_RDWR | O_NONBLOCK);
313         ASSERTF(fd2 >= 0, "open failed for '%s': %s",
314                 mainpath, strerror(errno));
315
316         /* Valid command first. */
317         gid = 1234;
318         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
319         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
320         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
321         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
322
323         /* Lock on one fd, unlock on the other */
324         gid = 6947556;
325         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
326         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
327         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
328         ASSERTF(rc == -1 && errno == EINVAL,
329                 "unexpected unlock retval: %d %s", rc, strerror(errno));
330         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
331         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
332
333         /* Lock from both */
334         gid = 89489665;
335         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
336         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
337         rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
338         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
339         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
340         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
341         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
342         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
343
344         /* Lock from both. Unlock in reverse order. */
345         gid = 89489665;
346         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
347         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
348         rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid);
349         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
350         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
351         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
352         rc = ioctl(fd2, LL_IOC_GROUP_UNLOCK, gid);
353         ASSERTF(rc == 0, "cannot unlock '%s': %s", mainpath, strerror(errno));
354
355         /* Try to lock with different gids */
356         gid = 89489665;
357         rc = ioctl(fd1, LL_IOC_GROUP_LOCK, gid);
358         ASSERTF(rc == 0, "cannot lock '%s': %s", mainpath, strerror(errno));
359         for (gid2 = -50; gid2 < 50; gid2++) {
360                 rc = ioctl(fd2, LL_IOC_GROUP_LOCK, gid2);
361                 if (gid2 == 0)
362                         ASSERTF(rc == -1 && errno == EINVAL,
363                                 "unexpected lock retval for gid %d: %s",
364                                 gid2, strerror(errno));
365                 else
366                         ASSERTF(rc == -1 && errno == EAGAIN,
367                                 "unexpected lock retval for gid %d: %s",
368                                 gid2, strerror(errno));
369         }
370         rc = ioctl(fd1, LL_IOC_GROUP_UNLOCK, gid);
371         ASSERTF(rc == 0, "cannot unlock '%s': %s",
372                 mainpath, strerror(errno));
373
374         close(fd1);
375         close(fd2);
376 }
377
378 static void usage(char *prog)
379 {
380         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
381         exit(EXIT_FAILURE);
382 }
383
384 static void process_args(int argc, char *argv[])
385 {
386         int c;
387
388         while ((c = getopt(argc, argv, "d:")) != -1) {
389                 switch (c) {
390                 case 'd':
391                         lustre_dir = optarg;
392                         break;
393                 case '?':
394                 default:
395                         fprintf(stderr, "Unknown option '%c'\n", optopt);
396                         usage(argv[0]);
397                         break;
398                 }
399         }
400 }
401
402 int main(int argc, char *argv[])
403 {
404         char fsname[8];
405         int rc;
406
407         process_args(argc, argv);
408         if (lustre_dir == NULL)
409                 lustre_dir = "/mnt/lustre";
410
411         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
412         if (rc != 0) {
413                 fprintf(stderr, "Error: '%s': not a Lustre filesystem\n",
414                         lustre_dir);
415                 return EXIT_FAILURE;
416         }
417
418         /* Play nice with Lustre test scripts. Non-line buffered output
419          * stream under I/O redirection may appear incorrectly. */
420         setvbuf(stdout, NULL, _IOLBF, 0);
421
422         /* Create a test filename and reuse it. Remove possibly old files. */
423         rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, maindir);
424         ASSERTF(rc > 0 && rc < sizeof(mainpath), "invalid name for mainpath");
425         cleanup();
426
427         atexit(cleanup);
428
429         PERFORM(test10);
430         PERFORM(test11);
431         PERFORM(test20);
432         PERFORM(test30);
433
434         return EXIT_SUCCESS;
435 }