Whamcloud - gitweb
6436b63da8e4928bed917e588165441bf2f48a4e
[fs/lustre-release.git] / lustre / tests / mirror_io.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  * Copyright (c) 2017, Intel Corporation. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * lustre/tests/mirror_io.c
31  *
32  * Lustre mirror test tool.
33  *
34  * Author: Jinshan Xiong <jinshan.xiong@intel.com>
35  */
36
37 #include <stdio.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <stdlib.h>
41 #include <errno.h>
42 #include <time.h>
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <err.h>
46
47 #include <lustre/lustreapi.h>
48
49 #define syserr(exp, str, args...)                       \
50 do {                                                    \
51         if (exp)                                        \
52                 err(EXIT_FAILURE, str, ##args);         \
53 } while (0)
54
55 #define syserrx(exp, str, args...)                      \
56 do {                                                    \
57         if (exp)                                        \
58                 errx(EXIT_FAILURE, str, ##args);        \
59 } while (0)
60
61 #define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
62
63 static const char *progname;
64
65 static void usage(void);
66
67 static int open_file(const char *fname)
68 {
69         struct stat stbuf;
70         int fd;
71
72         if (stat(fname, &stbuf) < 0)
73                 err(1, "%s", fname);
74
75         if (!S_ISREG(stbuf.st_mode))
76                 errx(1, "%s: '%s' is not a regular file", progname, fname);
77
78         fd = open(fname, O_DIRECT | O_RDWR);
79         syserr(fd < 0, "open %s", fname);
80
81         return fd;
82 }
83
84 static size_t get_ids(int fd, unsigned int *ids)
85 {
86         struct llapi_layout *layout;
87         size_t count = 0;
88         int rc;
89
90         layout = llapi_layout_get_by_fd(fd, 0);
91         syserrx(layout == NULL, "layout is NULL");
92
93         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
94         syserrx(rc < 0, "first component");
95
96         do {
97                 unsigned int id;
98
99                 rc = llapi_layout_mirror_id_get(layout, &id);
100                 syserrx(rc < 0, "id get");
101
102                 if (!count || ids[count - 1] != id)
103                         ids[count++] = id;
104
105                 rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
106                 syserrx(rc < 0, "move to next");
107         } while (rc == 0);
108
109         llapi_layout_free(layout);
110
111         return count;
112 }
113
114 static void check_id(int fd, unsigned int id)
115 {
116         unsigned int ids[LUSTRE_MIRROR_COUNT_MAX];
117         size_t count;
118         bool found = false;
119         int i;
120
121         count = get_ids(fd, ids);
122         for (i = 0; i < count; i++) {
123                 if (id == ids[i]) {
124                         found = true;
125                         break;
126                 }
127         }
128
129         syserr(!found, "cannot find the mirror id: %d", id);
130 }
131
132 static void mirror_dump(int argc, char *argv[])
133 {
134         const char *outfile = NULL;
135         int id = -1;
136         int fd;
137         int outfd;
138         int c;
139         const size_t buflen = 4 * 1024 * 1024;
140         void *buf;
141         off_t pos;
142
143         opterr = 0;
144         while ((c = getopt(argc, argv, "i:o:")) != -1) {
145                 switch (c) {
146                 case 'i':
147                         id = atol(optarg);
148                         break;
149
150                 case 'o':
151                         outfile = optarg;
152                         break;
153
154                 default:
155                         errx(1, "unknown option: '%s'", argv[optind - 1]);
156                 }
157         }
158
159         if (argc > optind + 1)
160                 errx(1, "too many files");
161         if (argc == optind)
162                 errx(1, "no file name given");
163
164         syserrx(id < 0, "mirror id is not set");
165
166         fd = open_file(argv[optind]);
167
168         check_id(fd, id);
169
170         if (outfile) {
171                 outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
172                 syserr(outfd < 0, "open %s", outfile);
173         } else {
174                 outfd = STDOUT_FILENO;
175         }
176
177         c = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
178         syserr(c, "posix_memalign");
179
180         pos = 0;
181         while (1) {
182                 ssize_t bytes_read;
183                 ssize_t written;
184
185                 bytes_read = llapi_mirror_read(fd, id, buf, buflen, pos);
186                 if (!bytes_read)
187                         break;
188
189                 syserrx(bytes_read < 0, "mirror read");
190
191                 written = write(outfd, buf, bytes_read);
192                 syserrx(written < bytes_read, "short write");
193
194                 pos += bytes_read;
195         }
196
197         fsync(outfd);
198         close(outfd);
199
200         close(fd);
201
202         free(buf);
203 }
204
205 static size_t add_tids(unsigned int *ids, size_t count, char *arg)
206 {
207         while (*arg) {
208                 char *end;
209                 char *tmp;
210                 int id;
211                 int i;
212
213                 tmp = strchr(arg, ',');
214                 if (tmp)
215                         *tmp = 0;
216
217                 id = strtol(arg, &end, 10);
218                 syserrx(*end || id <= 0, "id string error: '%s'", arg);
219
220                 for (i = 0; i < count; i++)
221                         syserrx(id == ids[i], "duplicate id: %d", id);
222
223                 ids[count++] = (unsigned int)id;
224
225                 if (!tmp)
226                         break;
227
228                 arg = tmp + 1;
229         }
230
231         return count;
232 }
233
234 static void mirror_copy(int argc, char *argv[])
235 {
236         int id = -1;
237         int fd;
238         int c;
239         int i;
240
241         unsigned int ids[4096] = { 0 };
242         size_t count = 0;
243         ssize_t result;
244
245         opterr = 0;
246         while ((c = getopt(argc, argv, "i:t:")) != -1) {
247                 switch (c) {
248                 case 'i':
249                         id = atol(optarg);
250                         break;
251
252                 case 't':
253                         count = add_tids(ids, count, optarg);
254                         break;
255
256                 default:
257                         errx(1, "unknown option: '%s'", argv[optind - 1]);
258                 }
259         }
260
261         if (argc > optind + 1)
262                 errx(1, "too many files");
263         if (argc == optind)
264                 errx(1, "no file name given");
265
266         syserrx(id < 0, "mirror id is not set");
267
268         for (i = 0; i < count; i++)
269                 syserrx(id == ids[i], "src and dst have the same id");
270
271         fd = open_file(argv[optind]);
272
273         check_id(fd, id);
274
275         result = llapi_mirror_copy_many(fd, id, ids, count);
276         syserrx(result < 0, "copy error: %zd", result);
277
278         fprintf(stdout, "mirror copied successfully: ");
279         for (i = 0; i < result; i++)
280                 fprintf(stdout, "%d ", ids[i]);
281         fprintf(stdout, "\n");
282
283         close(fd);
284 }
285
286 /* XXX - does not work. Leave here as place holder */
287 static void mirror_ost_lv(int argc, char *argv[])
288 {
289         int id = -1;
290         int fd;
291         int c;
292         int rc;
293         __u32 layout_version;
294
295         opterr = 0;
296         while ((c = getopt(argc, argv, "i:")) != -1) {
297                 switch (c) {
298                 case 'i':
299                         id = atol(optarg);
300                         break;
301
302                 default:
303                         errx(1, "unknown option: '%s'", argv[optind - 1]);
304                 }
305         }
306
307         if (argc > optind + 1)
308                 errx(1, "too many files");
309         if (argc == optind)
310                 errx(1, "no file name given");
311
312         syserrx(id < 0, "mirror id is not set");
313
314         fd = open_file(argv[optind]);
315
316         check_id(fd, id);
317
318         rc = llapi_mirror_set(fd, id);
319         syserr(rc < 0, "set mirror id error");
320
321         rc = llapi_get_ost_layout_version(fd, &layout_version);
322         syserr(rc < 0, "get ostlayoutversion error");
323
324         llapi_mirror_clear(fd);
325         close(fd);
326
327         fprintf(stdout, "ostlayoutversion: %u\n", layout_version);
328 }
329
330 static void usage_wrapper(int argc, char *argv[])
331 {
332         usage();
333 }
334
335 const struct subcommand {
336         const char *name;
337         void (*func)(int argc, char *argv[]);
338         const char *helper;
339 } cmds[] = {
340         { "dump", mirror_dump, "dump mirror: <-i id> [-o file] FILE" },
341         { "copy", mirror_copy, "copy mirror: <-i id> <-t id1,id2> FILE" },
342         { "data_version", mirror_ost_lv, "ost layout version: <-i id> FILE" },
343         { "help", usage_wrapper, "print helper message" },
344 };
345
346 static void usage(void)
347 {
348         int i;
349
350         fprintf(stdout, "%s <command> [OPTIONS] [<FILE>]\n", progname);
351         for (i = 0; i < ARRAY_SIZE(cmds); i++)
352                 fprintf(stdout, "\t%s - %s\n", cmds[i].name, cmds[i].helper);
353
354         exit(0);
355 }
356
357 int main(int argc, char *argv[])
358 {
359         bool found = false;
360         int i;
361
362         progname = basename(argv[0]);
363         if (argc < 3)
364                 usage();
365
366         for (i = 0; i < ARRAY_SIZE(cmds); i++) {
367                 if (strcmp(cmds[i].name, argv[1]))
368                         continue;
369
370                 found = true;
371                 cmds[i].func(argc - 1, argv + 1);
372                 break;
373         }
374
375         if (!found) {
376                 syserrx(1, "unknown subcommand: '%s'", argv[1]);
377                 exit(EXIT_FAILURE);
378         }
379         exit(EXIT_SUCCESS);
380 }