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.sun.com/software/products/lustre/docs/GPLv2.pdf
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
27 * Copyright (c) 2017, Intel Corporation. All rights reserved.
28 * Use is subject to license terms.
30 * lustre/tests/mirror_io.c
32 * Lustre mirror test tool.
34 * Author: Jinshan Xiong <jinshan.xiong@intel.com>
43 #include <sys/types.h>
45 #include <sys/param.h>
48 #include <uapi/linux/lustre/lustre_idl.h>
49 #include <lustre/lustreapi.h>
51 #define syserr(exp, str, args...) \
54 errx(EXIT_FAILURE, "%d: "str, __LINE__, ##args); \
57 #define syserrx(exp, str, args...) \
60 errx(EXIT_FAILURE, "%d: "str, __LINE__, ##args); \
63 #define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
65 static const char *progname;
67 static void usage(void);
69 static int open_file(const char *fname)
74 if (stat(fname, &stbuf) < 0)
77 if (!S_ISREG(stbuf.st_mode))
78 errx(1, "%s: '%s' is not a regular file", progname, fname);
80 fd = open(fname, O_DIRECT | O_RDWR);
81 syserr(fd < 0, "open %s", fname);
86 static size_t get_ids(int fd, unsigned int *ids)
88 struct llapi_layout *layout;
92 layout = llapi_layout_get_by_fd(fd, 0);
93 syserrx(layout == NULL, "layout is NULL");
95 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
96 syserrx(rc < 0, "first component");
101 rc = llapi_layout_mirror_id_get(layout, &id);
102 syserrx(rc < 0, "id get");
104 if (!count || ids[count - 1] != id)
107 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
108 syserrx(rc < 0, "move to next");
111 llapi_layout_free(layout);
116 static void check_id(int fd, unsigned int id)
118 unsigned int ids[LUSTRE_MIRROR_COUNT_MAX];
123 count = get_ids(fd, ids);
124 for (i = 0; i < count; i++) {
131 syserr(!found, "cannot find the mirror id: %d", id);
134 static void mirror_dump(int argc, char *argv[])
136 const char *outfile = NULL;
141 const size_t buflen = 4 * 1024 * 1024;
146 while ((c = getopt(argc, argv, "i:o:")) != -1) {
157 errx(1, "unknown option: '%s'", argv[optind - 1]);
161 if (argc > optind + 1)
162 errx(1, "too many files");
164 errx(1, "no file name given");
166 syserrx(id < 0, "mirror id is not set");
168 fd = open_file(argv[optind]);
173 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
174 syserr(outfd < 0, "open %s", outfile);
176 outfd = STDOUT_FILENO;
179 c = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
180 syserr(c, "posix_memalign");
187 bytes_read = llapi_mirror_read(fd, id, buf, buflen, pos);
191 syserrx(bytes_read < 0, "mirror read");
193 written = write(outfd, buf, bytes_read);
194 syserrx(written < bytes_read, "short write");
207 static size_t add_tids(unsigned int *ids, size_t count, char *arg)
215 tmp = strchr(arg, ',');
219 id = strtol(arg, &end, 10);
220 syserrx(*end || id <= 0, "id string error: '%s'", arg);
222 for (i = 0; i < count; i++)
223 syserrx(id == ids[i], "duplicate id: %d", id);
225 ids[count++] = (unsigned int)id;
236 static void mirror_copy(int argc, char *argv[])
243 unsigned int ids[4096] = { 0 };
248 while ((c = getopt(argc, argv, "i:t:")) != -1) {
255 count = add_tids(ids, count, optarg);
259 errx(1, "unknown option: '%s'", argv[optind - 1]);
263 if (argc > optind + 1)
264 errx(1, "too many files");
266 errx(1, "no file name given");
268 syserrx(id < 0, "mirror id is not set");
270 for (i = 0; i < count; i++)
271 syserrx(id == ids[i], "src and dst have the same id");
273 fd = open_file(argv[optind]);
277 result = llapi_mirror_copy_many(fd, id, ids, count);
278 syserrx(result < 0, "copy error: %zd", result);
280 fprintf(stdout, "mirror copied successfully: ");
281 for (i = 0; i < result; i++)
282 fprintf(stdout, "%d ", ids[i]);
283 fprintf(stdout, "\n");
288 /* XXX - does not work. Leave here as place holder */
289 static void mirror_ost_lv(int argc, char *argv[])
295 __u32 layout_version;
298 while ((c = getopt(argc, argv, "i:")) != -1) {
305 errx(1, "unknown option: '%s'", argv[optind - 1]);
309 if (argc > optind + 1)
310 errx(1, "too many files");
312 errx(1, "no file name given");
314 syserrx(id < 0, "mirror id is not set");
316 fd = open_file(argv[optind]);
320 rc = llapi_mirror_set(fd, id);
321 syserr(rc < 0, "set mirror id error");
323 rc = llapi_get_ost_layout_version(fd, &layout_version);
324 syserr(rc < 0, "get ostlayoutversion error");
326 llapi_mirror_clear(fd);
329 fprintf(stdout, "ostlayoutversion: %u\n", layout_version);
333 AFTER_RESYNC_START = 1 << 0,
334 INVALID_IDS = 1 << 1,
335 ZERO_RESYNC_IDS = 1 << 2,
336 DELAY_BEFORE_COPY = 1 << 3,
337 OPEN_TEST_FILE = 1 << 4,
340 static enum resync_errors resync_parse_error(const char *arg)
344 enum resync_errors error;
346 { "resync_start", AFTER_RESYNC_START },
347 { "invalid_ids", INVALID_IDS },
348 { "zero_resync_ids", ZERO_RESYNC_IDS },
349 { "delay_before_copy", DELAY_BEFORE_COPY },
350 { "open_test_file", OPEN_TEST_FILE },
354 for (i = 0; i < ARRAY_SIZE(cmds); i++)
355 if (strcmp(arg, cmds[i].loc) == 0)
356 return cmds[i].error;
358 syserr(1, "unknown error string: %s", arg);
366 uint32_t id; /* component id */
370 /* find all stale components */
371 static size_t mirror_find_stale(struct llapi_layout *layout,
372 struct resync_comp *comp, size_t max_count)
377 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
378 syserr(rc < 0, "llapi_layout_comp_move");
386 rc = llapi_layout_mirror_id_get(layout, &mirror_id);
387 syserr(rc < 0, "llapi_layout_comp_id_get");
389 rc = llapi_layout_comp_id_get(layout, &id);
390 syserr(rc < 0, "llapi_layout_comp_id_get");
392 rc = llapi_layout_comp_flags_get(layout, &flags);
393 syserr(rc < 0, "llapi_layout_comp_flags_get");
395 rc = llapi_layout_comp_extent_get(layout, &start, &end);
396 syserr(rc < 0, "llapi_layout_comp_flags_get");
398 if (flags & LCME_FL_STALE) {
400 comp[idx].mirror_id = mirror_id;
401 comp[idx].start = start;
405 syserr(idx >= max_count, "array too small");
408 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
409 syserr(rc < 0, "llapi_layout_comp_move");
415 /* locate @layout to a valid component covering file [file_start, file_end) */
416 static uint32_t mirror_find(struct llapi_layout *layout,
417 uint64_t file_start, uint64_t file_end, uint64_t *endp)
419 uint32_t mirror_id = 0;
422 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
423 syserr(rc < 0, "llapi_layout_comp_move");
428 uint32_t flags, id, rid;
430 llapi_layout_mirror_id_get(layout, &rid);
431 syserr(rc < 0, "llapi_layout_mirror_id_get");
433 rc = llapi_layout_comp_id_get(layout, &id);
434 syserr(rc < 0, "llapi_layout_comp_id_get");
436 rc = llapi_layout_comp_flags_get(layout, &flags);
437 syserr(rc < 0, "llapi_layout_comp_flags_get");
439 rc = llapi_layout_comp_extent_get(layout, &start, &end);
440 syserr(rc < 0, "llapi_layout_comp_extent_get");
442 if (!(flags & LCME_FL_STALE)) {
443 if (file_start >= start && file_start < end) {
446 else if (mirror_id != rid || *endp != start)
449 file_start = *endp = end;
455 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
456 syserr(rc < 0, "llapi_layout_comp_move");
462 static char *endstr(uint64_t end)
466 if (end == (uint64_t)-1)
469 snprintf(buf, sizeof(buf), "%lx", end);
473 static ssize_t mirror_resync_one(int fd, struct llapi_layout *layout,
474 uint32_t dst, uint64_t start, uint64_t end)
480 if (end == OBD_OBJECT_EOF)
481 count = OBD_OBJECT_EOF;
490 src = mirror_find(layout, start, end, &mirror_end);
491 syserr(!src, "could find component covering %lu\n", start);
493 if (mirror_end == OBD_OBJECT_EOF)
496 to_copy = MIN(count, mirror_end - start);
498 copied = llapi_mirror_copy(fd, src, dst, start, to_copy);
499 syserr(copied < 0, "llapi_mirror_copy returned %zd\n", copied);
501 printf("src (%u) [%lx -> %s) -> dst (%u), copied %zd bytes\n",
502 src, start, endstr(mirror_end), dst, copied);
505 if (copied < to_copy) /* end of file */
508 if (count != OBD_OBJECT_EOF)
516 static void mirror_resync(int argc, char *argv[])
519 int error_inject = 0;
526 struct llapi_layout *layout;
527 struct ll_ioc_lease *ioc;
528 struct resync_comp comp_array[1024] = { { 0 } };
529 size_t comp_size = 0;
533 while ((c = getopt(argc, argv, "e:d:")) != -1) {
536 error_inject |= resync_parse_error(optarg);
539 delay = atol(optarg);
542 errx(1, "unknown option: '%s'", argv[optind - 1]);
546 if (argc > optind + 1)
547 errx(1, "too many files");
549 errx(1, "no file name given");
551 fname = argv[optind];
552 fd = open_file(fname);
554 /* set the lease on the file */
555 ioc = calloc(sizeof(*ioc) + sizeof(__u32) * 4096, 1);
556 syserr(ioc == NULL, "no memory");
558 ioc->lil_mode = LL_LEASE_WRLCK;
559 ioc->lil_flags = LL_LEASE_RESYNC;
560 rc = llapi_lease_get_ext(fd, ioc);
561 syserr(rc < 0, "llapi_lease_get_ext resync");
563 if (error_inject & AFTER_RESYNC_START)
564 syserrx(1, "hit by error injection");
566 layout = llapi_layout_get_by_fd(fd, 0);
567 syserr(layout == NULL, "llapi_layout_get_by_fd");
569 rc = llapi_layout_flags_get(layout, &flr_state);
570 syserr(rc, "llapi_layout_flags_get");
572 flr_state &= LCM_FL_FLR_MASK;
573 syserrx(flr_state != LCM_FL_WRITE_PENDING &&
574 flr_state != LCM_FL_SYNC_PENDING,
575 "file state error: %d", flr_state);
577 if (error_inject & DELAY_BEFORE_COPY)
580 comp_size = mirror_find_stale(layout, comp_array,
581 ARRAY_SIZE(comp_array));
583 printf("%s: found %zd stale components\n", fname, comp_size);
586 while (idx < comp_size) {
592 rc = llapi_lease_check(fd);
593 syserr(rc != LL_LEASE_WRLCK, "lost lease lock");
595 mirror_id = comp_array[idx].mirror_id;
596 end = comp_array[idx].end;
598 printf("%s: resyncing mirror: %u, components: %u ",
599 fname, mirror_id, comp_array[idx].id);
601 for (i = idx + 1; i < comp_size; i++) {
602 if (mirror_id != comp_array[i].mirror_id ||
603 end != comp_array[i].start)
606 printf("%u ", comp_array[i].id);
607 end = comp_array[i].end;
611 res = mirror_resync_one(fd, layout, mirror_id,
612 comp_array[idx].start, end);
616 printf("components synced: ");
617 for (j = idx; j < i; j++) {
618 comp_array[j].synced = true;
619 printf("%u ", comp_array[j].id);
624 syserrx(res < 0, "llapi_mirror_copy_many");
629 /* prepare ioc for lease put */
630 ioc->lil_mode = LL_LEASE_UNLCK;
631 ioc->lil_flags = LL_LEASE_RESYNC_DONE;
633 for (idx = 0; idx < comp_size; idx++) {
634 if (comp_array[idx].synced) {
635 ioc->lil_ids[ioc->lil_count] = comp_array[idx].id;
640 if (error_inject & ZERO_RESYNC_IDS)
643 if (error_inject & INVALID_IDS && ioc->lil_count > 0)
644 ioc->lil_ids[ioc->lil_count - 1] = 567; /* inject error */
646 llapi_layout_free(layout);
648 if (error_inject & OPEN_TEST_FILE) /* break lease */
649 close(open(argv[optind], O_RDONLY));
651 rc = llapi_lease_get_ext(fd, ioc);
652 syserr(rc < 0, "llapi_lease_get_ext resync done");
654 syserr(rc == 0, "file busy");
659 static void usage_wrapper(int argc, char *argv[])
664 const struct subcommand {
666 void (*func)(int argc, char *argv[]);
669 { "dump", mirror_dump, "dump mirror: <-i id> [-o file] FILE" },
670 { "copy", mirror_copy, "copy mirror: <-i id> <-t id1,id2> FILE" },
671 { "data_version", mirror_ost_lv, "ost layout version: <-i id> FILE" },
672 { "resync", mirror_resync,
673 "resync mirrors: [-e error] [-d delay] FILE" },
674 { "help", usage_wrapper, "print helper message" },
677 static void usage(void)
681 fprintf(stdout, "%s <command> [OPTIONS] [<FILE>]\n", progname);
682 for (i = 0; i < ARRAY_SIZE(cmds); i++)
683 fprintf(stdout, "\t%s - %s\n", cmds[i].name, cmds[i].helper);
688 int main(int argc, char *argv[])
693 progname = basename(argv[0]);
697 for (i = 0; i < ARRAY_SIZE(cmds); i++) {
698 if (strcmp(cmds[i].name, argv[1]))
702 cmds[i].func(argc - 1, argv + 1);
707 syserrx(1, "unknown subcommand: '%s'", argv[1]);