Whamcloud - gitweb
LU-8055 ldev: File system label filtering
[fs/lustre-release.git] / lustre / tests / llapi_fid_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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26
27 /*
28  * Copyright 2014 Cray Inc, all rights reserved.
29  * Author: Frank Zago.
30  *
31  * A few portions are extracted from llapi_layout_test.c
32  *
33  * The purpose of this test is to test the llapi fid related function
34  * (fid2path, path2fid, ...)
35  *
36  * The program will exit as soon a non zero error code is returned.
37  */
38
39 #include <stdlib.h>
40 #include <errno.h>
41 #include <getopt.h>
42 #include <fcntl.h>
43 #include <unistd.h>
44 #include <poll.h>
45 #include <sys/ioctl.h>
46 #include <time.h>
47
48 #include <lustre/lustreapi.h>
49 #include <lustre/lustre_idl.h>
50
51 #define ERROR(fmt, ...)                                                 \
52         fprintf(stderr, "%s: %s:%d: %s: " fmt "\n",                     \
53                 program_invocation_short_name, __FILE__, __LINE__,      \
54                 __func__, ## __VA_ARGS__);
55
56 #define DIE(fmt, ...)                  \
57         do {                           \
58                 ERROR(fmt, ## __VA_ARGS__);     \
59                 exit(EXIT_FAILURE);             \
60         } while (0)
61
62 #define ASSERTF(cond, fmt, ...)                                         \
63         do {                                                            \
64                 if (!(cond))                                            \
65                         DIE("assertion '%s' failed: "fmt,               \
66                             #cond, ## __VA_ARGS__);                     \
67         } while (0)
68
69 #define PERFORM(testfn) \
70         do {                                                            \
71                 cleanup();                                              \
72                 fprintf(stderr, "Starting test " #testfn " at %lld\n",  \
73                         (unsigned long long)time(NULL));                \
74                 testfn();                                               \
75                 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
76                        (unsigned long long)time(NULL));                 \
77                 cleanup();                                              \
78         } while (0)
79
80 /* Name of file/directory. Will be set once and will not change. */
81 static char mainpath[PATH_MAX];
82 static const char *maindir = "llapi_fid_test_name_9585766";
83
84 static char fsmountdir[PATH_MAX];       /* Lustre mountpoint */
85 static char *lustre_dir;                /* Test directory inside Lustre */
86
87 /* Cleanup our test directory. */
88 static void cleanup(void)
89 {
90         char cmd[PATH_MAX];
91         int rc;
92
93         rc = snprintf(cmd, sizeof(cmd), "rm -rf -- '%s'", mainpath);
94         ASSERTF(rc > 0 && rc < sizeof(cmd),
95                 "invalid delete command for path '%s'", mainpath);
96         rc = system(cmd);
97         ASSERTF(rc != -1, "Cannot execute rm command");
98         ASSERTF(WEXITSTATUS(rc) == 0,
99                 "rm command returned %d", WEXITSTATUS(rc));
100 }
101
102 /* Helper - call path2fid, fd2fid and fid2path against an existing
103  * file/directory */
104 static void helper_fid2path(const char *filename, int fd)
105 {
106         lustre_fid fid;
107         lustre_fid fid2;
108         lustre_fid fid3;
109         char fidstr[FID_LEN + 1];
110         char path1[PATH_MAX];
111         char path2[PATH_MAX];
112         char path3[PATH_MAX];
113         long long recno1;
114         long long recno2;
115         int linkno1;
116         int linkno2;
117         int rc;
118
119         rc = llapi_path2fid(filename, &fid);
120         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
121                 filename, strerror(-rc));
122
123         /* Without braces */
124         snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
125         recno1 = -1;
126         linkno1 = 0;
127         rc = llapi_fid2path(lustre_dir, fidstr, path1,
128                             sizeof(path1), &recno1, &linkno1);
129         ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
130                 fidstr, strerror(-rc));
131
132         /* Same with braces */
133         snprintf(fidstr, sizeof(fidstr), DFID, PFID(&fid));
134         recno2 = -1;
135         linkno2 = 0;
136         rc = llapi_fid2path(lustre_dir, fidstr, path2,
137                             sizeof(path2), &recno2, &linkno2);
138         ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
139                 fidstr, strerror(-rc));
140
141         /* Make sure both calls to llapi_fid2path returned the same
142          * data. */
143         ASSERTF(strcmp(path1, path2) == 0, "paths are different: '%s' / '%s'",
144                 path1, path2);
145         ASSERTF(recno1 == recno2, "recnos are different: %lld / %lld",
146                 recno1, recno2);
147         ASSERTF(linkno1 == linkno2, "linknos are different: %d / %d",
148                 linkno1, linkno2);
149
150         /* Try fd2fid and check that the result is still the same. */
151         if (fd != -1) {
152                 rc = llapi_fd2fid(fd, &fid3);
153                 ASSERTF(rc == 0, "llapi_fd2fid failed for '%s': %s",
154                         mainpath, strerror(-rc));
155
156                 ASSERTF(memcmp(&fid, &fid3, sizeof(fid)) == 0,
157                         "fids are different");
158         }
159
160         /* Pass the result back to fid2path and ensure the fid stays
161          * the same. */
162         rc = snprintf(path3, sizeof(path3), "%s/%s", fsmountdir, path1);
163         ASSERTF((rc > 0 && rc < sizeof(path3)), "invalid name");
164         rc = llapi_path2fid(path3, &fid2);
165         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
166                 path3, strerror(-rc));
167         ASSERTF(memcmp(&fid, &fid2, sizeof(fid)) == 0, "fids are different");
168 }
169
170 /* Test helper_fid2path */
171 static void test10(void)
172 {
173         int rc;
174         int fd;
175         struct stat statbuf;
176
177         /* Against Lustre root */
178         helper_fid2path(lustre_dir, -1);
179
180         /* Against a regular file */
181         fd = creat(mainpath, 0);
182         ASSERTF(fd >= 0, "creat failed for '%s': %s",
183                 mainpath, strerror(errno));
184         helper_fid2path(mainpath, fd);
185         close(fd);
186         rc = unlink(mainpath);
187         ASSERTF(rc == 0, "unlink failed for '%s': %s",
188                 mainpath, strerror(errno));
189
190         /* Against a pipe */
191         rc = mkfifo(mainpath, 0);
192         ASSERTF(rc == 0, "mkfifo failed for '%s': %s",
193                 mainpath, strerror(errno));
194         helper_fid2path(mainpath, -1);
195         rc = unlink(mainpath);
196         ASSERTF(rc == 0, "unlink failed for '%s': %s",
197                 mainpath, strerror(errno));
198
199         /* Against a directory */
200         rc = mkdir(mainpath, 0);
201         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
202                 mainpath, strerror(errno));
203         helper_fid2path(mainpath, -1);
204         rc = rmdir(mainpath);
205         ASSERTF(rc == 0, "rmdir failed for '%s': %s",
206                 mainpath, strerror(errno));
207
208         /* Against a char device. Use same as /dev/null in case things
209          * go wrong. */
210         rc = stat("/dev/null", &statbuf);
211         ASSERTF(rc == 0, "stat failed for /dev/null: %s", strerror(errno));
212         rc = mknod(mainpath, S_IFCHR, statbuf.st_rdev);
213         ASSERTF(rc == 0, "mknod failed for '%s': %s",
214                 mainpath, strerror(errno));
215         helper_fid2path(mainpath, -1);
216         rc = unlink(mainpath);
217         ASSERTF(rc == 0, "unlink failed for '%s': %s",
218                 mainpath, strerror(errno));
219
220         /* Against a block device device. Reuse same dev. */
221         rc = mknod(mainpath, S_IFBLK, statbuf.st_rdev);
222         ASSERTF(rc == 0, "mknod failed for '%s': %s",
223                 mainpath, strerror(errno));
224         helper_fid2path(mainpath, -1);
225         rc = unlink(mainpath);
226         ASSERTF(rc == 0, "unlink failed for '%s': %s",
227                 mainpath, strerror(errno));
228
229         /* Against a socket. */
230         rc = mknod(mainpath, S_IFSOCK, (dev_t)0);
231         ASSERTF(rc == 0, "mknod failed for '%s': %s",
232                 mainpath, strerror(errno));
233         helper_fid2path(mainpath, -1);
234         rc = unlink(mainpath);
235         ASSERTF(rc == 0, "unlink failed for '%s': %s",
236                 mainpath, strerror(errno));
237 }
238
239 /* Test against deleted files. */
240 static void test11(void)
241 {
242         int rc;
243         int fd;
244         lustre_fid fid;
245         char fidstr[FID_LEN + 1];
246         char path[PATH_MAX];
247         long long recno;
248         int linkno;
249
250         /* Against a regular file */
251         fd = creat(mainpath, 0);
252         ASSERTF(fd >= 0, "creat failed for '%s': %s",
253                 mainpath, strerror(errno));
254         close(fd);
255
256         rc = llapi_path2fid(mainpath, &fid);
257         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
258                 mainpath, strerror(-rc));
259
260         rc = unlink(mainpath);
261         ASSERTF(rc == 0, "unlink failed for '%s': %s",
262                 mainpath, strerror(errno));
263
264         snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
265         recno = -1;
266         linkno = 0;
267         rc = llapi_fid2path(lustre_dir, fidstr, path,
268                             sizeof(path), &recno, &linkno);
269         ASSERTF(rc == -ENOENT, "llapi_fid2path failed for fid %s: %s",
270                 fidstr, strerror(-rc));
271 }
272
273 /* Test volatile file. */
274 static void test12(void)
275 {
276         int rc;
277         int fd;
278         int fd2;
279         int fd3;
280         lustre_fid fid;
281
282         /* Against a volatile file */
283         rc = mkdir(mainpath, 0);
284         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
285                 mainpath, strerror(errno));
286         fd = llapi_create_volatile_idx(mainpath, -1, 0600);
287         ASSERTF(fd >= 0, "creat failed for '%s': %s",
288                 mainpath, strerror(errno));
289
290         rc = llapi_fd2fid(fd, &fid);
291         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
292                 mainpath, strerror(-rc));
293
294         /* No many ways to test, except to open by fid. */
295         fd2 = llapi_open_by_fid(mainpath, &fid, 0600);
296         ASSERTF(fd2 >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
297                 PFID(&fid), strerror(errno));
298
299         close(fd);
300
301         /* Check the file can still be opened, since fd2 is not
302          * closed. */
303         fd3 = llapi_open_by_fid(mainpath, &fid, 0600);
304         ASSERTF(fd3 >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
305                 PFID(&fid), strerror(errno));
306
307         close(fd2);
308         close(fd3);
309
310         /* The volatile file is gone now. */
311         fd = llapi_open_by_fid(mainpath, &fid, 0600);
312         ASSERTF(fd < 0, "llapi_open_by_fid for " DFID_NOBRACE ": %d",
313                 PFID(&fid), fd);
314 }
315
316 /* Test with sub directories */
317 static void test20(void)
318 {
319         char testpath[PATH_MAX];
320         size_t len;
321         int dir_created = 0;
322         int rc;
323
324         rc = snprintf(testpath, sizeof(testpath), "%s", mainpath);
325         ASSERTF((rc > 0 && rc < sizeof(testpath)),
326                 "invalid name for testpath '%s'", mainpath);
327
328         rc = mkdir(testpath, S_IRWXU);
329         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
330                 testpath, strerror(errno));
331
332         len = strlen(testpath);
333
334         /* Create subdirectories as long as we can. Each new subdir is
335          * "/x", so we need at least 3 characters left in testpath. */
336         while (len <= sizeof(testpath) - 3) {
337                 strncat(testpath, "/x", 2);
338
339                 len += 2;
340
341                 rc = mkdir(testpath, S_IRWXU);
342                 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
343                         testpath, strerror(errno));
344
345                 dir_created++;
346
347                 helper_fid2path(testpath, -1);
348         }
349
350         /* And test the last one. */
351         helper_fid2path(testpath, -1);
352
353         /* Make sure we have created enough directories. Even with a
354          * reasonably long mountpath, we should have created at least
355          * 2000. */
356         ASSERTF(dir_created >= 2000, "dir_created=%d -- '%s'",
357                 dir_created, testpath);
358 }
359
360 /* Test linkno from fid2path */
361 static void test30(void)
362 {
363         /* Note that since the links are stored in the extended
364          * attributes, only a few of these will fit (about 150 in this
365          * test). Still, create more than that to ensure the system
366          * doesn't break. See LU-5746. */
367         const int num_links = 1000;
368         struct {
369                 char filename[PATH_MAX];
370                 bool seen;
371         } links[num_links];
372         char buf[PATH_MAX];
373         char buf2[PATH_MAX];
374         lustre_fid fid;
375         char fidstr[FID_LEN + 1];
376         int rc;
377         int i;
378         int j;
379         int fd;
380         int linkno;
381         bool past_link_limit = false;
382
383         /* Create the containing directory. */
384         rc = mkdir(mainpath, 0);
385         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
386                 mainpath, strerror(errno));
387
388         /* Initializes the link array. */
389         for (i = 0; i < num_links; i++) {
390                 rc = snprintf(links[i].filename, sizeof(links[i].filename),
391                               "%s/%s/link%04d", lustre_dir, maindir, i);
392
393                 ASSERTF((rc > 0 && rc < sizeof(links[i].filename)),
394                         "invalid name for link");
395
396                 links[i].seen = false;
397         }
398
399         /* Create the original file. */
400         fd = creat(links[0].filename, 0);
401         ASSERTF(fd >= 0, "create failed for '%s': %s",
402                 links[0].filename, strerror(errno));
403         close(fd);
404
405         rc = llapi_path2fid(links[0].filename, &fid);
406         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
407                 links[0].filename, strerror(-rc));
408         snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
409
410         /* Create the links */
411         for (i = 1; i < num_links; i++) {
412                 rc = link(links[0].filename, links[i].filename);
413                 ASSERTF(rc == 0, "link failed for '%s' / '%s': %s",
414                         links[0].filename, links[i].filename, strerror(errno));
415         }
416
417         /* Query the links, making sure we got all of them */
418         for (i = 0; i < num_links + 10; i++) {
419                 long long recno;
420                 bool found;
421
422                 /* Without braces */
423                 recno = -1;
424                 linkno = i;
425                 rc = llapi_fid2path(links[0].filename, fidstr, buf,
426                                     sizeof(buf), &recno, &linkno);
427                 ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
428                         fidstr, strerror(-rc));
429
430                 snprintf(buf2, sizeof(buf2), "%s/%s", fsmountdir, buf);
431
432                 if (past_link_limit == false) {
433                         /* Find the name in the links that were created */
434                         found = false;
435                         for (j = 0; j < num_links; j++) {
436                                 if (strcmp(buf2, links[j].filename) == 0) {
437                                         ASSERTF(links[j].seen == false,
438                                                 "link '%s' already seen",
439                                                 links[j].filename);
440                                         links[j].seen = true;
441                                         found = true;
442                                         break;
443                                 }
444                         }
445                         ASSERTF(found == true, "link '%s' not found", buf2);
446
447                         if (linkno == i) {
448                                 /* The linkno hasn't changed. This
449                                  * means it is the last entry
450                                  * stored. */
451                                 past_link_limit = true;
452
453                                 fprintf(stderr,
454                                         "Was able to store %d links in the EA\n",
455                                         i);
456
457                                 /* Also assume that some links were
458                                  * returned. It's hard to compute the
459                                  * exact value. */
460                                 ASSERTF(i > 50,
461                                         "not enough links were returned: %d",
462                                         i);
463                         }
464                 } else {
465                         /* Past the number of links stored in the EA,
466                          * Lustre will simply return the original
467                          * file. */
468                         ASSERTF(strcmp(buf2, links[0].filename) == 0,
469                                        "unexpected link for record %d: '%s' / '%s'",
470                                        i, buf2, links[0].filename);
471                 }
472
473         }
474 }
475
476 /* Test llapi_fd2parent/llapi_path2parent on mainpath (whatever its
477  * type). mainpath must exist. */
478 static void help_test40(void)
479 {
480         lustre_fid parent_fid;
481         lustre_fid fid2;
482         char buf[PATH_MAX];
483         int rc;
484
485         /* Successful call */
486         memset(buf, 0x55, sizeof(buf));
487         rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, PATH_MAX);
488         ASSERTF(rc == 0, "llapi_path2parent failed for '%s': %s",
489                 mainpath, strerror(errno));
490         ASSERTF(strcmp(buf, maindir) == 0, "paths are different: '%s' / '%s'",
491                 buf, maindir);
492
493         /* By construction, mainpath is just under lustre_dir, so we
494          * can check that the parent fid of mainpath is indeed the one
495          * of lustre_dir. */
496         rc = llapi_path2fid(lustre_dir, &fid2);
497         ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
498                 lustre_dir, strerror(-rc));
499         ASSERTF(memcmp(&parent_fid, &fid2, sizeof(fid2)) == 0,
500                 "fids are different");
501
502         /* Name too short */
503         rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, 0);
504         ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
505
506         rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, 5);
507         ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
508
509         rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, strlen(maindir));
510         ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
511
512         rc = llapi_path2parent(mainpath, 0, &parent_fid, buf,
513                                strlen(maindir)+1);
514         ASSERTF(rc == 0, "llapi_path2parent failed: %s", strerror(-rc));
515 }
516
517 static void test40(void)
518 {
519         int fd;
520         int rc;
521
522         /* Against a directory. */
523         rc = mkdir(mainpath, 0);
524         ASSERTF(rc == 0, "mkdir failed for '%s': %s",
525                 mainpath, strerror(errno));
526         help_test40();
527
528         cleanup();
529
530         /* Against a regular file */
531         fd = creat(mainpath, 0);
532         ASSERTF(fd >= 0, "creat failed for '%s': %s",
533                 mainpath, strerror(errno));
534         close(fd);
535 }
536
537 /* Test LL_IOC_GETPARENT directly */
538 static void test41(void)
539 {
540         int rc;
541         int fd;
542         int i;
543         union {
544                 struct getparent gp;
545                 char buf[1024];
546         } u;
547
548         /* Against a regular file */
549         fd = creat(mainpath, 0);
550         ASSERTF(fd >= 0, "creat failed for '%s': %s",
551                 mainpath, strerror(errno));
552
553         /* Ask a few times */
554         for (i = 0; i < 256; i++) {
555                 memset(u.buf, i, sizeof(u.buf)); /* poison */
556                 u.gp.gp_linkno = 0;
557                 u.gp.gp_name_size = 100;
558
559                 rc = ioctl(fd, LL_IOC_GETPARENT, &u.gp);
560                 ASSERTF(rc == 0, "LL_IOC_GETPARENT failed: %s, rc=%d",
561                         strerror(errno), rc);
562                 ASSERTF(strcmp(u.gp.gp_name, maindir) == 0,
563                         "strings are different: %zd, %zd",
564                         strlen(u.gp.gp_name), strlen(maindir));
565         }
566
567         close(fd);
568 }
569
570 /* Test with linkno. Create sub directories, and put a link to the
571  * original file in them. */
572 static void test42(void)
573 {
574
575         const int num_links = 100;
576         struct {
577                 char subdir[PATH_MAX];
578                 lustre_fid subdir_fid;
579                 char filename[PATH_MAX];
580                 bool seen;
581         } links[num_links];
582         char link0[PATH_MAX];
583         char buf[PATH_MAX];
584         int rc;
585         int i;
586         int fd;
587         int linkno;
588         lustre_fid parent_fid;
589
590         /* Create the containing directory. */
591         rc = mkdir(mainpath, 0);
592         ASSERTF(rc == 0, "mkdir failed: for '%s': %s",
593                 mainpath, strerror(errno));
594
595         /* Initializes the link array. */
596         for (i = 0; i < num_links; i++) {
597                 rc = snprintf(links[i].subdir, sizeof(links[i].subdir),
598                               "%s/sub%04d", mainpath, i);
599                 ASSERTF((rc > 0 && rc < sizeof(links[i].subdir)),
600                         "invalid name for subdir");
601
602                 rc = snprintf(links[i].filename, sizeof(links[i].filename),
603                               "link%04d", i);
604                 ASSERTF((rc > 0 && rc < sizeof(links[i].filename)),
605                         "invalid name for link");
606
607                 links[i].seen = false;
608         }
609
610         /* Create the subdirectories. */
611         for (i = 0; i < num_links; i++) {
612                 rc = mkdir(links[i].subdir, S_IRWXU);
613                 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
614                         links[i].subdir, strerror(errno));
615
616                 rc = llapi_path2fid(links[i].subdir, &links[i].subdir_fid);
617                 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
618                         links[i].subdir, strerror(-rc));
619         }
620
621         /* Create the original file. */
622         rc = snprintf(link0, sizeof(link0), "%s/%s",
623                       links[0].subdir, links[0].filename);
624         ASSERTF((rc > 0 && rc < sizeof(link0)), "invalid name for file");
625
626         fd = creat(link0, 0);
627         ASSERTF(fd >= 0, "create failed for '%s': %s", link0, strerror(errno));
628         close(fd);
629
630         /* Create the links */
631         for (i = 1; i < num_links; i++) {
632                 rc = snprintf(buf, sizeof(buf), "%s/%s",
633                               links[i].subdir, links[i].filename);
634                 ASSERTF((rc > 0 && rc < sizeof(buf)),
635                         "invalid name for link %d", i);
636
637                 rc = link(link0, buf);
638                 ASSERTF(rc == 0, "link failed for '%s' / '%s': %s",
639                         link0, buf, strerror(errno));
640         }
641
642         /* Query the links, making sure we got all of them. Do it in
643          * reverse order, just because! */
644         for (linkno = num_links-1; linkno >= 0; linkno--) {
645                 bool found;
646
647                 rc = llapi_path2parent(link0, linkno, &parent_fid, buf,
648                                        sizeof(buf));
649                 ASSERTF(rc == 0, "llapi_path2parent failed for '%s': %s",
650                         link0, strerror(-rc));
651
652                 /* Find the name in the links that were created */
653                 found = false;
654                 for (i = 0; i < num_links; i++) {
655                         if (memcmp(&parent_fid, &links[i].subdir_fid,
656                                    sizeof(parent_fid)) != 0)
657                                 continue;
658
659                         ASSERTF(strcmp(links[i].filename, buf) == 0,
660                                 "name differ: '%s' / '%s'",
661                                 links[i].filename, buf);
662                         ASSERTF(links[i].seen == false,
663                                 "link '%s' already seen", links[i].filename);
664                         links[i].seen = true;
665                         found = true;
666                         break;
667                 }
668                 ASSERTF(found == true, "link '%s' not found", buf);
669         }
670
671         /* check non existent n+1 link */
672         rc = llapi_path2parent(link0, num_links, &parent_fid, buf, sizeof(buf));
673         ASSERTF(rc == -ENODATA, "llapi_path2parent error for '%s': %s",
674                 link0, strerror(-rc));
675 }
676
677 static void usage(char *prog)
678 {
679         fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
680         exit(EXIT_FAILURE);
681 }
682
683 static void process_args(int argc, char *argv[])
684 {
685         int c;
686
687         while ((c = getopt(argc, argv, "d:")) != -1) {
688                 switch (c) {
689                 case 'd':
690                         lustre_dir = optarg;
691                         break;
692                 case '?':
693                 default:
694                         fprintf(stderr, "Unknown option '%c'\n", optopt);
695                         usage(argv[0]);
696                 }
697         }
698 }
699
700 int main(int argc, char *argv[])
701 {
702         char fsname[8 + 1];
703         int rc;
704
705         process_args(argc, argv);
706         if (lustre_dir == NULL)
707                 lustre_dir = "/mnt/lustre";
708
709         rc = llapi_search_mounts(lustre_dir, 0, fsmountdir, fsname);
710         if (rc != 0) {
711                 fprintf(stderr, "Error: %s: not a Lustre filesystem\n",
712                         lustre_dir);
713                 return EXIT_FAILURE;
714         }
715
716         /* Play nice with Lustre test scripts. Non-line buffered output
717          * stream under I/O redirection may appear incorrectly. */
718         setvbuf(stdout, NULL, _IOLBF, 0);
719
720         /* Create a test filename and reuse it. Remove possibly old files. */
721         rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, maindir);
722         ASSERTF((rc > 0 && rc < sizeof(mainpath)), "invalid name for mainpath");
723         cleanup();
724
725         atexit(cleanup);
726
727         PERFORM(test10);
728         PERFORM(test11);
729         PERFORM(test12);
730         PERFORM(test20);
731         PERFORM(test30);
732         PERFORM(test40);
733         PERFORM(test41);
734         PERFORM(test42);
735
736         return EXIT_SUCCESS;
737 }