4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
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.
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).
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
24 * Copyright 2014 Cray Inc, all rights reserved.
26 * Copyright (c) 2016, Intel Corporation.
30 * A few portions are extracted from llapi_layout_test.c
32 * The purpose of this test is to test the llapi fid related function
33 * (fid2path, path2fid, ...)
35 * The program will exit as soon a non zero error code is returned.
44 #include <sys/ioctl.h>
47 #include <lustre/lustreapi.h>
48 #include <linux/lustre/lustre_fid.h>
50 #define ERROR(fmt, ...) \
51 fprintf(stderr, "%s: %s:%d: %s: " fmt "\n", \
52 program_invocation_short_name, __FILE__, __LINE__, \
53 __func__, ## __VA_ARGS__);
55 #define DIE(fmt, ...) \
57 ERROR(fmt, ## __VA_ARGS__); \
61 #define ASSERTF(cond, fmt, ...) \
64 DIE("assertion '%s' failed: "fmt, \
65 #cond, ## __VA_ARGS__); \
68 #define PERFORM(testfn) \
71 fprintf(stderr, "Starting test " #testfn " at %lld\n", \
72 (unsigned long long)time(NULL)); \
74 fprintf(stderr, "Finishing test " #testfn " at %lld\n", \
75 (unsigned long long)time(NULL)); \
79 /* Name of file/directory. Will be set once and will not change. */
80 static char mainpath[PATH_MAX];
81 static const char *maindir = "llapi_fid_test_name_9585766";
83 static char mnt_dir[PATH_MAX]; /* Lustre mountpoint */
84 static int mnt_fd = -1;
85 static char *lustre_dir; /* Test directory inside Lustre */
87 /* Cleanup our test directory. */
88 static void cleanup(void)
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);
97 ASSERTF(rc != -1, "Cannot execute rm command");
98 ASSERTF(WEXITSTATUS(rc) == 0,
99 "rm command returned %d", WEXITSTATUS(rc));
102 /* Helper - call path2fid, fd2fid and fid2path against an existing
105 static void helper_fid2path(const char *filename, int fd)
110 char fidstr[FID_LEN + 1];
111 char path1[PATH_MAX];
112 char path2[PATH_MAX];
113 char path3[PATH_MAX];
120 rc = llapi_path2fid(filename, &fid);
121 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
122 filename, strerror(-rc));
125 snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
128 rc = llapi_fid2path(lustre_dir, fidstr, path1,
129 sizeof(path1), &recno1, &linkno1);
130 ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
131 fidstr, strerror(-rc));
133 /* Same with braces */
134 snprintf(fidstr, sizeof(fidstr), DFID, PFID(&fid));
137 rc = llapi_fid2path(lustre_dir, fidstr, path2,
138 sizeof(path2), &recno2, &linkno2);
139 ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
140 fidstr, strerror(-rc));
142 /* Make sure both calls to llapi_fid2path returned the same data. */
143 ASSERTF(strcmp(path1, path2) == 0, "paths are different: '%s' / '%s'",
145 ASSERTF(recno1 == recno2, "recnos are different: %lld / %lld",
147 ASSERTF(linkno1 == linkno2, "linknos are different: %d / %d",
150 /* Use llapi_fid2path_at() */
153 rc = llapi_fid2path_at(mnt_fd, &fid, path2, sizeof(path2),
155 ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
156 fidstr, strerror(-rc));
158 /* Make sure both calls to llapi_fid2path returned the same data. */
159 ASSERTF(strcmp(path1, path2) == 0, "paths are different: '%s' / '%s'",
161 ASSERTF(recno1 == recno2, "recnos are different: %lld / %lld",
163 ASSERTF(linkno1 == linkno2, "linknos are different: %d / %d",
166 /* Try fd2fid and check that the result is still the same. */
168 rc = llapi_fd2fid(fd, &fid3);
169 ASSERTF(rc == 0, "llapi_fd2fid failed for '%s': %s",
170 mainpath, strerror(-rc));
172 ASSERTF(memcmp(&fid, &fid3, sizeof(fid)) == 0,
173 "fids are different");
176 /* Pass result back to fid2path and ensure the fid stays the same. */
177 rc = snprintf(path3, sizeof(path3), "%s/%s", mnt_dir, path1);
178 ASSERTF((rc > 0 && rc < sizeof(path3)), "invalid name");
179 rc = llapi_path2fid(path3, &fid2);
180 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
181 path3, strerror(-rc));
182 ASSERTF(memcmp(&fid, &fid2, sizeof(fid)) == 0, "fids are different");
185 /* Test helper_fid2path */
186 static void test10(void)
192 /* Against Lustre root */
193 helper_fid2path(lustre_dir, -1);
195 /* Against a regular file */
196 fd = creat(mainpath, 0);
197 ASSERTF(fd >= 0, "creat failed for '%s': %s",
198 mainpath, strerror(errno));
199 helper_fid2path(mainpath, fd);
201 rc = unlink(mainpath);
202 ASSERTF(rc == 0, "unlink failed for '%s': %s",
203 mainpath, strerror(errno));
206 rc = mkfifo(mainpath, 0);
207 ASSERTF(rc == 0, "mkfifo failed for '%s': %s",
208 mainpath, strerror(errno));
209 helper_fid2path(mainpath, -1);
210 rc = unlink(mainpath);
211 ASSERTF(rc == 0, "unlink failed for '%s': %s",
212 mainpath, strerror(errno));
214 /* Against a directory */
215 rc = mkdir(mainpath, 0);
216 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
217 mainpath, strerror(errno));
218 helper_fid2path(mainpath, -1);
219 rc = rmdir(mainpath);
220 ASSERTF(rc == 0, "rmdir failed for '%s': %s",
221 mainpath, strerror(errno));
223 /* Against a char device. Use same as /dev/null in case things
226 rc = stat("/dev/null", &statbuf);
227 ASSERTF(rc == 0, "stat failed for /dev/null: %s", strerror(errno));
228 rc = mknod(mainpath, S_IFCHR, statbuf.st_rdev);
229 ASSERTF(rc == 0, "mknod failed for '%s': %s",
230 mainpath, strerror(errno));
231 helper_fid2path(mainpath, -1);
232 rc = unlink(mainpath);
233 ASSERTF(rc == 0, "unlink failed for '%s': %s",
234 mainpath, strerror(errno));
236 /* Against a block device device. Reuse same dev. */
237 rc = mknod(mainpath, S_IFBLK, statbuf.st_rdev);
238 ASSERTF(rc == 0, "mknod failed for '%s': %s",
239 mainpath, strerror(errno));
240 helper_fid2path(mainpath, -1);
241 rc = unlink(mainpath);
242 ASSERTF(rc == 0, "unlink failed for '%s': %s",
243 mainpath, strerror(errno));
245 /* Against a socket. */
246 rc = mknod(mainpath, S_IFSOCK, (dev_t)0);
247 ASSERTF(rc == 0, "mknod failed for '%s': %s",
248 mainpath, strerror(errno));
249 helper_fid2path(mainpath, -1);
250 rc = unlink(mainpath);
251 ASSERTF(rc == 0, "unlink failed for '%s': %s",
252 mainpath, strerror(errno));
255 /* Test against deleted files. */
256 static void test11(void)
261 char fidstr[FID_LEN + 1];
266 /* Against a regular file */
267 fd = creat(mainpath, 0);
268 ASSERTF(fd >= 0, "creat failed for '%s': %s",
269 mainpath, strerror(errno));
272 rc = llapi_path2fid(mainpath, &fid);
273 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
274 mainpath, strerror(-rc));
276 rc = unlink(mainpath);
277 ASSERTF(rc == 0, "unlink failed for '%s': %s",
278 mainpath, strerror(errno));
280 snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
283 rc = llapi_fid2path(lustre_dir, fidstr, path,
284 sizeof(path), &recno, &linkno);
285 ASSERTF(rc == -ENOENT, "llapi_fid2path failed for fid %s: %s",
286 fidstr, strerror(-rc));
289 /* Test volatile file. */
290 static void test12(void)
298 /* Against a volatile file */
299 rc = mkdir(mainpath, 0);
300 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
301 mainpath, strerror(errno));
302 fd = llapi_create_volatile_idx(mainpath, -1, 0);
303 ASSERTF(fd >= 0, "creat failed for '%s': %s",
304 mainpath, strerror(errno));
306 rc = llapi_fd2fid(fd, &fid);
307 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
308 mainpath, strerror(-rc));
310 /* No many ways to test, except to open by fid. */
311 fd2 = llapi_open_by_fid(mainpath, &fid, O_RDONLY);
312 ASSERTF(fd2 >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
313 PFID(&fid), strerror(errno));
317 /* Check the file can still be opened, since fd2 is not closed. */
318 fd3 = llapi_open_by_fid(mainpath, &fid, O_RDONLY);
319 ASSERTF(fd3 >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
320 PFID(&fid), strerror(errno));
325 /* The volatile file is gone now. */
326 fd = llapi_open_by_fid(mainpath, &fid, O_RDONLY);
327 ASSERTF(fd < 0, "llapi_open_by_fid for " DFID_NOBRACE ": %d",
331 /* Test with sub directories */
332 static void test20(void)
334 char testpath[PATH_MAX];
339 rc = snprintf(testpath, sizeof(testpath), "%s", mainpath);
340 ASSERTF((rc > 0 && rc < sizeof(testpath)),
341 "invalid name for testpath '%s'", mainpath);
343 rc = mkdir(testpath, 0700);
344 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
345 testpath, strerror(errno));
347 len = strlen(testpath);
349 /* Create subdirectories as long as we can. Each new subdir is
350 * "/x", so we need at least 3 characters left in testpath.
352 while (len <= sizeof(testpath) - 3) {
353 strncat(testpath, "/x", sizeof(testpath) - 1);
357 rc = mkdir(testpath, 0700);
358 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
359 testpath, strerror(errno));
363 helper_fid2path(testpath, -1);
366 /* And test the last one. */
367 helper_fid2path(testpath, -1);
369 /* Make sure we have created enough directories. Even with a
370 * reasonably long mountpath, we should have created at least 2000.
372 ASSERTF(dir_created >= 2000, "dir_created=%d -- '%s'",
373 dir_created, testpath);
376 /* Test linkno from fid2path */
377 static void test30(void)
379 /* Note that since the links are stored in the extended attributes,
380 * only a few of these will fit (about 150 in this test). Still, create
381 * more than that to ensure the system doesn't break. See LU-5746.
383 const int num_links = 1000;
385 char filename[PATH_MAX];
389 char buf2[PATH_MAX * 2];
391 char fidstr[FID_LEN + 1];
397 bool past_link_limit = false;
399 /* Create the containing directory. */
400 rc = mkdir(mainpath, 0);
401 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
402 mainpath, strerror(errno));
404 /* Initializes the link array. */
405 for (i = 0; i < num_links; i++) {
406 rc = snprintf(links[i].filename, sizeof(links[i].filename),
407 "%s/%s/link%04d", lustre_dir, maindir, i);
409 ASSERTF((rc > 0 && rc < sizeof(links[i].filename)),
410 "invalid name for link");
412 links[i].seen = false;
415 /* Create the original file. */
416 fd = creat(links[0].filename, 0);
417 ASSERTF(fd >= 0, "create failed for '%s': %s",
418 links[0].filename, strerror(errno));
421 rc = llapi_path2fid(links[0].filename, &fid);
422 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
423 links[0].filename, strerror(-rc));
424 snprintf(fidstr, sizeof(fidstr), DFID_NOBRACE, PFID(&fid));
426 /* Create the links */
427 for (i = 1; i < num_links; i++) {
428 rc = link(links[0].filename, links[i].filename);
429 ASSERTF(rc == 0, "link failed for '%s' / '%s': %s",
430 links[0].filename, links[i].filename, strerror(errno));
433 /* Query the links, making sure we got all of them */
434 for (i = 0; i < num_links + 10; i++) {
441 rc = llapi_fid2path(links[0].filename, fidstr, buf,
442 sizeof(buf), &recno, &linkno);
443 ASSERTF(rc == 0, "llapi_fid2path failed for fid %s: %s",
444 fidstr, strerror(-rc));
446 snprintf(buf2, sizeof(buf2), "%s/%s", mnt_dir, buf);
448 if (past_link_limit == false) {
449 /* Find the name in the links that were created */
451 for (j = 0; j < num_links; j++) {
452 if (strcmp(buf2, links[j].filename) == 0) {
453 ASSERTF(links[j].seen == false,
454 "link '%s' already seen",
456 links[j].seen = true;
461 ASSERTF(found == true, "link '%s' not found", buf2);
464 /* The linkno hasn't changed. This means it is
465 * the last entry stored.
467 past_link_limit = true;
470 "Was able to store %d links in the EA\n",
473 /* Also assume that some links were returned.
474 * It's hard to compute the exact value.
477 "not enough links were returned: %d",
481 /* Past the number of links stored in the EA, Lustre
482 * will simply return the original file.
484 ASSERTF(strcmp(buf2, links[0].filename) == 0,
485 "unexpected link for record %d: '%s' / '%s'",
486 i, buf2, links[0].filename);
492 /* Test special FIDs for lustre */
493 static void test31(void)
497 fd = llapi_open_by_fid(mainpath, &LU_ROOT_FID, O_RDONLY);
498 ASSERTF(fd >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
499 PFID(&LU_ROOT_FID), strerror(errno));
501 fd = llapi_open_by_fid(mainpath, &LU_DOT_LUSTRE_FID, O_RDONLY);
502 ASSERTF(fd >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
503 PFID(&LU_DOT_LUSTRE_FID), strerror(errno));
505 fd = llapi_open_by_fid(mainpath, &LU_OBF_FID, O_RDONLY);
506 ASSERTF(fd >= 0, "llapi_open_by_fid for " DFID_NOBRACE ": %s",
507 PFID(&LU_OBF_FID), strerror(errno));
510 /* Test llapi_fd2parent/llapi_path2parent on mainpath (whatever its
511 * type). mainpath must exist.
513 static void help_test40(void)
515 struct lu_fid parent_fid;
520 /* Successful call */
521 memset(buf, 0x55, sizeof(buf));
522 rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, PATH_MAX);
523 ASSERTF(rc == 0, "llapi_path2parent failed for '%s': %s",
524 mainpath, strerror(errno));
525 ASSERTF(strcmp(buf, maindir) == 0, "paths are different: '%s' / '%s'",
528 /* By construction, mainpath is just under lustre_dir, so we
529 * can check that the parent fid of mainpath is indeed the one
532 rc = llapi_path2fid(lustre_dir, &fid2);
533 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
534 lustre_dir, strerror(-rc));
535 ASSERTF(memcmp(&parent_fid, &fid2, sizeof(fid2)) == 0,
536 "fids are different");
539 rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, 0);
540 ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
542 rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, 5);
543 ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
545 rc = llapi_path2parent(mainpath, 0, &parent_fid, buf, strlen(maindir));
546 ASSERTF(rc == -EOVERFLOW, "llapi_path2parent error: %s", strerror(-rc));
548 rc = llapi_path2parent(mainpath, 0, &parent_fid, buf,
550 ASSERTF(rc == 0, "llapi_path2parent failed: %s", strerror(-rc));
553 static void test40(void)
558 /* Against a directory. */
559 rc = mkdir(mainpath, 0);
560 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
561 mainpath, strerror(errno));
566 /* Against a regular file */
567 fd = creat(mainpath, 0);
568 ASSERTF(fd >= 0, "creat failed for '%s': %s",
569 mainpath, strerror(errno));
573 /* Test LL_IOC_GETPARENT directly */
574 static void test41(void)
584 /* Against a regular file */
585 fd = creat(mainpath, 0);
586 ASSERTF(fd >= 0, "creat failed for '%s': %s",
587 mainpath, strerror(errno));
589 /* Ask a few times */
590 for (i = 0; i < 256; i++) {
591 memset(u.buf, i, sizeof(u.buf)); /* poison */
593 u.gp.gp_name_size = 100;
595 rc = ioctl(fd, LL_IOC_GETPARENT, &u.gp);
596 ASSERTF(rc == 0, "LL_IOC_GETPARENT failed: %s, rc=%d",
597 strerror(errno), rc);
598 ASSERTF(strcmp(u.gp.gp_name, maindir) == 0,
599 "strings are different: %zd, %zd",
600 strlen(u.gp.gp_name), strlen(maindir));
606 /* Test with linkno. Create sub directories, and put a link to the
607 * original file in them.
609 static void test42(void)
612 const int num_links = 100;
614 char subdir[PATH_MAX];
615 struct lu_fid subdir_fid;
616 char filename[PATH_MAX];
619 char link0[PATH_MAX];
625 struct lu_fid parent_fid;
627 /* Create the containing directory. */
628 rc = mkdir(mainpath, 0);
629 ASSERTF(rc == 0, "mkdir failed: for '%s': %s",
630 mainpath, strerror(errno));
632 /* Initializes the link array. */
633 for (i = 0; i < num_links; i++) {
634 rc = snprintf(links[i].subdir, sizeof(links[i].subdir),
635 "%s/sub%04d", mainpath, i);
636 ASSERTF((rc > 0 && rc < sizeof(links[i].subdir)),
637 "invalid name for subdir");
639 rc = snprintf(links[i].filename, sizeof(links[i].filename),
641 ASSERTF((rc > 0 && rc < sizeof(links[i].filename)),
642 "invalid name for link");
644 links[i].seen = false;
647 /* Create the subdirectories. */
648 for (i = 0; i < num_links; i++) {
649 rc = mkdir(links[i].subdir, 0700);
650 ASSERTF(rc == 0, "mkdir failed for '%s': %s",
651 links[i].subdir, strerror(errno));
653 rc = llapi_path2fid(links[i].subdir, &links[i].subdir_fid);
654 ASSERTF(rc == 0, "llapi_path2fid failed for '%s': %s",
655 links[i].subdir, strerror(-rc));
658 /* Create the original file. */
659 rc = snprintf(link0, sizeof(link0), "%s/%s",
660 links[0].subdir, links[0].filename);
661 ASSERTF((rc > 0 && rc < sizeof(link0)), "invalid name for file");
663 fd = creat(link0, 0);
664 ASSERTF(fd >= 0, "create failed for '%s': %s", link0, strerror(errno));
667 /* Create the links */
668 for (i = 1; i < num_links; i++) {
669 rc = snprintf(buf, sizeof(buf), "%s/%s",
670 links[i].subdir, links[i].filename);
671 ASSERTF((rc > 0 && rc < sizeof(buf)),
672 "invalid name for link %d", i);
674 rc = link(link0, buf);
675 ASSERTF(rc == 0, "link failed for '%s' / '%s': %s",
676 link0, buf, strerror(errno));
679 /* Query the links, making sure we got all of them. Do it in
680 * reverse order, just because!
682 for (linkno = num_links-1; linkno >= 0; linkno--) {
685 rc = llapi_path2parent(link0, linkno, &parent_fid, buf,
687 ASSERTF(rc == 0, "llapi_path2parent failed for '%s': %s",
688 link0, strerror(-rc));
690 /* Find the name in the links that were created */
692 for (i = 0; i < num_links; i++) {
693 if (memcmp(&parent_fid, &links[i].subdir_fid,
694 sizeof(parent_fid)) != 0)
697 ASSERTF(strcmp(links[i].filename, buf) == 0,
698 "name differ: '%s' / '%s'",
699 links[i].filename, buf);
700 ASSERTF(links[i].seen == false,
701 "link '%s' already seen", links[i].filename);
702 links[i].seen = true;
706 ASSERTF(found == true, "link '%s' not found", buf);
709 /* check non existent n+1 link */
710 rc = llapi_path2parent(link0, num_links, &parent_fid, buf, sizeof(buf));
711 ASSERTF(rc == -ENODATA, "llapi_path2parent error for '%s': %s",
712 link0, strerror(-rc));
715 static void usage(char *prog)
717 fprintf(stderr, "Usage: %s [-d lustre_dir]\n", prog);
721 static void process_args(int argc, char *argv[])
725 while ((c = getopt(argc, argv, "d:")) != -1) {
732 fprintf(stderr, "Unknown option '%c'\n", optopt);
738 int main(int argc, char *argv[])
743 process_args(argc, argv);
744 if (lustre_dir == NULL)
745 lustre_dir = "/mnt/lustre";
747 rc = llapi_search_mounts(lustre_dir, 0, mnt_dir, fsname);
749 fprintf(stderr, "Error: %s: not a Lustre filesystem\n",
754 mnt_fd = open(mnt_dir, O_RDONLY|O_DIRECTORY);
755 ASSERTF(!(mnt_fd < 0), "cannot open '%s': %s\n", mnt_dir,
758 /* Play nice with Lustre test scripts. Non-line buffered output
759 * stream under I/O redirection may appear incorrectly.
761 setvbuf(stdout, NULL, _IOLBF, 0);
763 /* Create a test filename and reuse it. Remove possibly old files. */
764 rc = snprintf(mainpath, sizeof(mainpath), "%s/%s", lustre_dir, maindir);
765 ASSERTF((rc > 0 && rc < sizeof(mainpath)), "invalid name for mainpath");