Whamcloud - gitweb
LU-6210 utils: Use C99 struct initializers in lustre_fsck.c
[fs/lustre-release.git] / lustre / utils / lustre_lfsck.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,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License version 2 for more details.  A copy is
14  * included in the COPYING file that accompanied this code.
15
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2012, 2016, Intel Corporation.
24  */
25 /*
26  * lustre/utils/lustre_lfsck.c
27  *
28  * Lustre user-space tools for LFSCK.
29  *
30  * Author: Fan Yong <yong.fan@whamcloud.com>
31  */
32
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <getopt.h>
39 #include <sys/ioctl.h>
40 #include <time.h>
41
42 #include "obdctl.h"
43 #include "lustreapi_internal.h"
44
45 #include <lustre/lustre_lfsck_user.h>
46 #include <lnet/lnetctl.h>
47 #include <linux/lustre_ioctl.h>
48 /* Needs to be last to avoid clashes */
49 #include <libcfs/util/ioctl.h>
50 #include <libcfs/util/param.h>
51
52 static struct option long_opt_start[] = {
53         {"device",              required_argument, 0, 'M'},
54         {"all",                 no_argument,       0, 'A'},
55         {"create_ostobj",       optional_argument, 0, 'c'},
56         {"create-ostobj",       optional_argument, 0, 'c'},
57         {"create_mdtobj",       optional_argument, 0, 'C'},
58         {"create-mdtobj",       optional_argument, 0, 'C'},
59         {"delay_create_ostobj", optional_argument, 0, 'd'},
60         {"delay-create-ostobj", optional_argument, 0, 'd'},
61         {"error",               required_argument, 0, 'e'},
62         {"help",                no_argument,       0, 'h'},
63         {"dryrun",              optional_argument, 0, 'n'},
64         {"orphan",              no_argument,       0, 'o'},
65         {"reset",               no_argument,       0, 'r'},
66         {"speed",               required_argument, 0, 's'},
67         {"type",                required_argument, 0, 't'},
68         {"window_size",         required_argument, 0, 'w'},
69         {"window-size",         required_argument, 0, 'w'},
70         {0,                     0,                 0,  0 }
71 };
72
73 static struct option long_opt_stop[] = {
74         { .val = 'A',   .name = "all",          .has_arg = no_argument },
75         { .val = 'h',   .name = "help",         .has_arg = no_argument },
76         { .val = 'M',   .name = "device",       .has_arg = required_argument },
77         { .name = NULL } };
78
79 static struct option long_opt_query[] = {
80         { .val = 'h',   .name = "help",         .has_arg = no_argument },
81         { .val = 'M',   .name = "device",       .has_arg = required_argument },
82         { .val = 't',   .name = "type",         .has_arg = required_argument },
83         { .val = 'w',   .name = "wait",         .has_arg = no_argument },
84         { .name = NULL } };
85
86 struct lfsck_type_name {
87         char            *ltn_name;
88         enum lfsck_type  ltn_type;
89 };
90
91 static struct lfsck_type_name lfsck_types_names[] = {
92         { "scrub",      LFSCK_TYPE_SCRUB },
93         { "layout",     LFSCK_TYPE_LAYOUT },
94         { "namespace",  LFSCK_TYPE_NAMESPACE },
95         { "default",    LFSCK_TYPES_DEF },
96         { "all",        LFSCK_TYPES_SUPPORTED },
97         { NULL,         0 }
98 };
99
100 static enum lfsck_type lfsck_name2type(const char *name)
101 {
102         int i;
103
104         for (i = 0; lfsck_types_names[i].ltn_name != NULL; i++) {
105                 if (strcmp(lfsck_types_names[i].ltn_name, name) == 0)
106                         return lfsck_types_names[i].ltn_type;
107         }
108         return -1;
109 }
110
111 static const char *lfsck_type2name(__u16 type)
112 {
113         int i;
114
115         for (i = 0; lfsck_types_names[i].ltn_name != NULL; i++) {
116                 if (type == lfsck_types_names[i].ltn_type)
117                         return lfsck_types_names[i].ltn_name;
118         }
119
120         return NULL;
121 }
122
123 static void usage_start(void)
124 {
125         fprintf(stderr, "start LFSCK\n"
126                 "usage:\n"
127                 "lfsck_start [-M | --device {MDT,OST}_device]\n"
128                 "            [-A | --all] [-c | --create_ostobj [on | off]]\n"
129                 "            [-C | --create_mdtobj [on | off]]\n"
130                 "            [-d | --delay_create_ostobj [on | off]]\n"
131                 "            [-e | --error {continue | abort}] [-h | --help]\n"
132                 "            [-n | --dryrun [on | off]] [-o | --orphan]\n"
133                 "            [-r | --reset] [-s | --speed ops_per_sec_limit]\n"
134                 "            [-t | --type check_type[,check_type...]]\n"
135                 "            [-w | --window_size size]\n"
136                 "options:\n"
137                 "-M: device to start LFSCK/scrub on\n"
138                 "-A: start LFSCK on all nodes via the specified MDT device "
139                     "(see \"-M\" option) by single LFSCK command\n"
140                 "-c: create the lost OST-object for dangling LOV EA "
141                     "(default 'off', or 'on')\n"
142                 "-C: create the lost MDT-object for dangling name entry "
143                     "(default 'off', or 'on')\n"
144                 "-d: delay create the lost OST-object for dangling LOV EA "
145                     "until orphan OST-objects handled (default 'off', or 'on')\n"
146                 "-e: error handle mode (default 'continue', or 'abort')\n"
147                 "-h: this help message\n"
148                 "-n: check with no modification (default 'off', or 'on')\n"
149                 "-o: repair orphan OST-objects\n"
150                 "-r: reset scanning to the start of the device\n"
151                 "-s: maximum items to be scanned per second "
152                     "(default '%d' = no limit)\n"
153                 "-t: check type(s) to be performed (default all)\n"
154                 "-w: window size for async requests pipeline\n",
155                 LFSCK_SPEED_NO_LIMIT);
156 }
157
158 static void usage_stop(void)
159 {
160         fprintf(stderr, "stop LFSCK\n"
161                 "usage:\n"
162                 "lfsck_stop [-M | --device {MDT,OST}_device]\n"
163                 "           [-A | --all] [-h | --help]\n"
164                 "options:\n"
165                 "-M: device to stop LFSCK/scrub on\n"
166                 "-A: stop LFSCK on all nodes via the specified MDT device "
167                     "(see \"-M\" option) by single LFSCK command\n"
168                 "-h: this help message\n");
169 }
170
171 static void usage_query(void)
172 {
173         fprintf(stderr, "check the LFSCK global status\n"
174                 "usage:\n"
175                 "lfsck_query [-M | --device MDT_device] [-h | --help]\n"
176                 "            [-t | --type check_type[,check_type...]]\n"
177                 "            [-t | --wait]\n"
178                 "options:\n"
179                 "-M: device to query LFSCK on\n"
180                 "-t: LFSCK type(s) to be queried (default is all)\n"
181                 "-h: this help message\n"
182                 "-w: do not return until LFSCK not running\n");
183 }
184
185 static int lfsck_pack_dev(struct obd_ioctl_data *data, char *device, char *arg)
186 {
187         int len = strlen(arg) + 1;
188
189         if (len > MAX_OBD_NAME) {
190                 fprintf(stderr, "device name is too long. "
191                         "Valid length should be less than %d\n", MAX_OBD_NAME);
192                 return -EINVAL;
193         }
194
195         memcpy(device, arg, len);
196         data->ioc_inlbuf4 = device;
197         data->ioc_inllen4 = len;
198         data->ioc_dev = OBD_DEV_BY_DEVNAME;
199         return 0;
200 }
201
202 static int lfsck_get_dev_name(struct obd_ioctl_data *data, char *device,
203                               int types, bool multipe_devices)
204 {
205         glob_t param = { 0 };
206         char *ptr;
207         int rc;
208         int i;
209
210         rc = cfs_get_param_paths(&param, "mdd/*-MDT*");
211         if (rc) {
212                 if (multipe_devices || errno != ENOENT ||
213                     types & LFSCK_TYPE_NAMESPACE) {
214                         fprintf(stderr, "Fail to get device name: rc = %d\n."
215                                 "You can specify the device explicitly "
216                                 "via '-M' option.\n", rc);
217                         return rc;
218                 }
219
220                 rc = cfs_get_param_paths(&param, "obdfilter/*-OST*");
221                 if (rc) {
222                         fprintf(stderr, "Fail to get device name: rc = %d\n."
223                                 "You can specify the device explicitly "
224                                 "via '-M' option.\n", rc);
225                         return rc;
226                 }
227         }
228
229         if (param.gl_pathc == 1)
230                 goto pack;
231
232         if (!multipe_devices) {
233                 fprintf(stderr,
234                         "Detect multiple devices on current node. "
235                         "Please specify the device explicitly "
236                         "via '-M' option or '-A' option for all.\n");
237                 rc = -EINVAL;
238                 goto out;
239         }
240
241         ptr = strrchr(param.gl_pathv[0], '-');
242         if (ptr == NULL) {
243                 rc = -EINVAL;
244                 goto out;
245         }
246
247         for (i = 1; i < param.gl_pathc; i++) {
248                 char *ptr2 = strrchr(param.gl_pathv[i], '-');
249
250                 if (ptr2 == NULL) {
251                         rc = -EINVAL;
252                         goto out;
253                 }
254
255                 if ((ptr - param.gl_pathv[0]) != (ptr2 - param.gl_pathv[i]) ||
256                     strncmp(param.gl_pathv[0], param.gl_pathv[i],
257                             (ptr - param.gl_pathv[0])) != 0) {
258                         fprintf(stderr,
259                                 "Detect multiple filesystems on current node. "
260                                 "Please specify the device explicitly "
261                                 "via '-M' option.\n");
262                         rc = -EINVAL;
263                         goto out;
264                 }
265         }
266
267 pack:
268         rc = lfsck_pack_dev(data, device, basename(param.gl_pathv[0]));
269
270 out:
271         cfs_free_param_data(&param);
272
273         return rc;
274 }
275
276 int jt_lfsck_start(int argc, char **argv)
277 {
278         struct obd_ioctl_data data;
279         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
280         char device[MAX_OBD_NAME];
281         struct lfsck_start start;
282         char *optstring = "Ac::C::d::e:hM:n::ors:t:w:";
283         int opt, index, rc, val, i;
284
285         memset(&data, 0, sizeof(data));
286         memset(&start, 0, sizeof(start));
287         memset(device, 0, MAX_OBD_NAME);
288         start.ls_version = LFSCK_VERSION_V1;
289         start.ls_active = LFSCK_TYPES_ALL;
290
291         /* Reset the 'optind' for the case of getopt_long() called multiple
292          * times under the same lctl. */
293         optind = 0;
294         while ((opt = getopt_long(argc, argv, optstring, long_opt_start,
295                                   &index)) != EOF) {
296                 switch (opt) {
297                 case 'A':
298                         start.ls_flags |= LPF_ALL_TGT | LPF_BROADCAST;
299                         break;
300                 case 'c':
301                         if (optarg == NULL || strcmp(optarg, "on") == 0) {
302                                 start.ls_flags |= LPF_CREATE_OSTOBJ;
303                         } else if (strcmp(optarg, "off") != 0) {
304                                 fprintf(stderr, "invalid switch: -c '%s'. "
305                                         "valid switches are:\n"
306                                         "empty ('on'), or 'off' without space. "
307                                         "For example:\n"
308                                         "'-c', '-con', '-coff'\n", optarg);
309                                 return -EINVAL;
310                         }
311                         start.ls_valid |= LSV_CREATE_OSTOBJ;
312                         break;
313                 case 'C':
314                         if (optarg == NULL || strcmp(optarg, "on") == 0) {
315                                 start.ls_flags |= LPF_CREATE_MDTOBJ;
316                         } else if (strcmp(optarg, "off") != 0) {
317                                 fprintf(stderr, "invalid switch: -C '%s'. "
318                                         "valid switches are:\n"
319                                         "empty ('on'), or 'off' without space. "
320                                         "For example:\n"
321                                         "'-C', '-Con', '-Coff'\n", optarg);
322                                 return -EINVAL;
323                         }
324                         start.ls_valid |= LSV_CREATE_MDTOBJ;
325                         break;
326                 case 'd':
327                         if (optarg == NULL || strcmp(optarg, "on") == 0) {
328                                 start.ls_flags |= LPF_DELAY_CREATE_OSTOBJ;
329                         } else if (strcmp(optarg, "off") != 0) {
330                                 fprintf(stderr, "invalid switch: -c '%s'. "
331                                         "valid switches are:\n"
332                                         "empty ('on'), or 'off' without space. "
333                                         "For example:\n"
334                                         "'-c', '-con', '-coff'\n", optarg);
335                                 return -EINVAL;
336                         }
337                         start.ls_valid |= LSV_DELAY_CREATE_OSTOBJ;
338                         break;
339                 case 'e':
340                         if (strcmp(optarg, "abort") == 0) {
341                                 start.ls_flags |= LPF_FAILOUT;
342                         } else if (strcmp(optarg, "continue") != 0) {
343                                 fprintf(stderr, "invalid error mode: -e '%s'."
344                                         "valid modes are: "
345                                         "'continue' or 'abort'.\n", optarg);
346                                 return -EINVAL;
347                         }
348                         start.ls_valid |= LSV_ERROR_HANDLE;
349                         break;
350                 case 'h':
351                         usage_start();
352                         return 0;
353                 case 'M':
354                         rc = lfsck_pack_dev(&data, device, optarg);
355                         if (rc != 0)
356                                 return rc;
357                         break;
358                 case 'n':
359                         if (optarg == NULL || strcmp(optarg, "on") == 0) {
360                                 start.ls_flags |= LPF_DRYRUN;
361                         } else if (strcmp(optarg, "off") != 0) {
362                                 fprintf(stderr, "invalid switch: -n '%s'. "
363                                         "valid switches are:\n"
364                                         "empty ('on'), or 'off' without space. "
365                                         "For example:\n"
366                                         "'-n', '-non', '-noff'\n", optarg);
367                                 return -EINVAL;
368                         }
369                         start.ls_valid |= LSV_DRYRUN;
370                         break;
371                 case 'o':
372                         start.ls_flags |= LPF_ALL_TGT | LPF_BROADCAST |
373                                           LPF_OST_ORPHAN;
374                         break;
375                 case 'r':
376                         start.ls_flags |= LPF_RESET;
377                         break;
378                 case 's':
379                         val = atoi(optarg);
380                         start.ls_speed_limit = val;
381                         start.ls_valid |= LSV_SPEED_LIMIT;
382                         break;
383                 case 't': {
384                         char *typename;
385
386                         if (start.ls_active == LFSCK_TYPES_ALL)
387                                 start.ls_active = 0;
388                         while ((typename = strsep(&optarg, ",")) != NULL) {
389                                 enum lfsck_type type;
390
391                                 type = lfsck_name2type(typename);
392                                 if (type == -1)
393                                         goto bad_type;
394                                 start.ls_active |= type;
395                         }
396                         break;
397 bad_type:
398                         fprintf(stderr, "invalid check type -t '%s'. "
399                                 "valid types are:\n", typename);
400                         for (i = 0; lfsck_types_names[i].ltn_name != NULL; i++)
401                                 fprintf(stderr, "%s%s", i != 0 ? "," : "",
402                                         lfsck_types_names[i].ltn_name);
403                         fprintf(stderr, "\n");
404                         return -EINVAL;
405                 }
406                 case 'w':
407                         val = atoi(optarg);
408                         if (val < 1 || val > LFSCK_ASYNC_WIN_MAX) {
409                                 fprintf(stderr,
410                                         "Invalid async window size that "
411                                         "may cause memory issues. The valid "
412                                         "range is [1 - %u].\n",
413                                         LFSCK_ASYNC_WIN_MAX);
414                                 return -EINVAL;
415                         }
416
417                         start.ls_async_windows = val;
418                         start.ls_valid |= LSV_ASYNC_WINDOWS;
419                         break;
420                 default:
421                         fprintf(stderr, "Invalid option, '-h' for help.\n");
422                         return -EINVAL;
423                 }
424         }
425
426         if (start.ls_active == LFSCK_TYPES_ALL)
427                 start.ls_active = LFSCK_TYPES_DEF;
428
429         if (data.ioc_inlbuf4 == NULL) {
430                 rc = lfsck_get_dev_name(&data, device, start.ls_active,
431                                         start.ls_flags & LPF_ALL_TGT);
432                 if (rc != 0)
433                         return rc;
434         }
435
436         data.ioc_inlbuf1 = (char *)&start;
437         data.ioc_inllen1 = sizeof(start);
438         memset(buf, 0, sizeof(rawbuf));
439         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
440         if (rc != 0) {
441                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
442                 return rc;
443         }
444
445         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_START_LFSCK, buf);
446         if (rc < 0) {
447                 perror("Fail to start LFSCK");
448                 return rc;
449         }
450
451         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
452         printf("Started LFSCK on the device %s: scrub", device);
453         for (i = 0; lfsck_types_names[i].ltn_name != NULL; i++) {
454                 if (start.ls_active & lfsck_types_names[i].ltn_type) {
455                         printf(" %s", lfsck_types_names[i].ltn_name);
456                         start.ls_active &= ~lfsck_types_names[i].ltn_type;
457                 }
458         }
459         if (start.ls_active != 0)
460                 printf(" unknown(0x%x)", start.ls_active);
461         printf("\n");
462
463         return 0;
464 }
465
466 int jt_lfsck_stop(int argc, char **argv)
467 {
468         struct obd_ioctl_data data;
469         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
470         char device[MAX_OBD_NAME];
471         struct lfsck_stop stop;
472         char *optstring = "AhM:";
473         int opt, index, rc;
474
475         memset(&data, 0, sizeof(data));
476         memset(&stop, 0, sizeof(stop));
477         memset(device, 0, MAX_OBD_NAME);
478
479         /* Reset the 'optind' for the case of getopt_long() called multiple
480          * times under the same lctl. */
481         optind = 0;
482         while ((opt = getopt_long(argc, argv, optstring, long_opt_stop,
483                                   &index)) != EOF) {
484                 switch (opt) {
485                 case 'A':
486                         stop.ls_flags |= LPF_ALL_TGT | LPF_BROADCAST;
487                         break;
488                 case 'h':
489                         usage_stop();
490                         return 0;
491                 case 'M':
492                         rc = lfsck_pack_dev(&data, device, optarg);
493                         if (rc != 0)
494                                 return rc;
495                         break;
496                 default:
497                         fprintf(stderr, "Invalid option, '-h' for help.\n");
498                         return -EINVAL;
499                 }
500         }
501
502         if (data.ioc_inlbuf4 == NULL) {
503                 rc = lfsck_get_dev_name(&data, device, 0,
504                                         stop.ls_flags & LPF_ALL_TGT);
505                 if (rc != 0)
506                         return rc;
507         }
508
509         data.ioc_inlbuf1 = (char *)&stop;
510         data.ioc_inllen1 = sizeof(stop);
511         memset(buf, 0, sizeof(rawbuf));
512         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
513         if (rc != 0) {
514                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
515                 return rc;
516         }
517
518         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_STOP_LFSCK, buf);
519         if (rc < 0) {
520                 perror("Fail to stop LFSCK");
521                 return rc;
522         }
523
524         printf("Stopped LFSCK on the device %s.\n", device);
525         return 0;
526 }
527
528 int jt_lfsck_query(int argc, char **argv)
529 {
530         struct obd_ioctl_data data = { 0 };
531         char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
532         char device[MAX_OBD_NAME] = "";
533         struct lfsck_query query = { .lu_types = LFSCK_TYPES_ALL };
534         int opt, index, rc, i;
535         enum lfsck_type type;
536
537         while ((opt = getopt_long(argc, argv, "hM:t:w", long_opt_query,
538                                   &index)) != EOF) {
539                 switch (opt) {
540                 case 'h':
541                         usage_query();
542                         return 0;
543                 case 'M':
544                         rc = lfsck_pack_dev(&data, device, optarg);
545                         if (rc != 0)
546                                 return rc;
547                         break;
548                 case 't': {
549                         char *typename;
550
551                         if (query.lu_types == LFSCK_TYPES_ALL)
552                                 query.lu_types = 0;
553                         while ((typename = strsep(&optarg, ",")) != NULL) {
554                                 type = lfsck_name2type(typename);
555                                 if (type == -1)
556                                         goto bad_type;
557                                 query.lu_types |= type;
558                         }
559                         break;
560
561 bad_type:
562                         fprintf(stderr, "invalid LFSCK type -t '%s'. "
563                                 "valid types are:\n", typename);
564                         for (i = 0; lfsck_types_names[i].ltn_name != NULL; i++)
565                                 fprintf(stderr, "%s%s", i != 0 ? "," : "",
566                                         lfsck_types_names[i].ltn_name);
567                         fprintf(stderr, "\n");
568                         return -EINVAL;
569                 }
570                 case 'w':
571                         query.lu_flags |= LPF_WAIT;
572                         break;
573                 default:
574                         fprintf(stderr, "Invalid option, '-h' for help.\n");
575                         usage_query();
576                         return -EINVAL;
577                 }
578         }
579
580         if (data.ioc_inlbuf4 == NULL) {
581                 rc = lfsck_get_dev_name(&data, device, 0, true);
582                 if (rc != 0)
583                         return rc;
584         }
585
586         data.ioc_inlbuf1 = (char *)&query;
587         data.ioc_inllen1 = sizeof(query);
588         memset(buf, 0, sizeof(rawbuf));
589         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
590         if (rc != 0) {
591                 fprintf(stderr, "Fail to pack ioctl data: rc = %d.\n", rc);
592                 return rc;
593         }
594
595         rc = l_ioctl(OBD_DEV_ID, OBD_IOC_QUERY_LFSCK, buf);
596         if (rc < 0) {
597                 perror("Fail to query LFSCK");
598                 return rc;
599         }
600
601         obd_ioctl_unpack(&data, buf, sizeof(rawbuf));
602         for (i = 0, type = 1 << i; i < LFSCK_TYPE_BITS; i++, type = 1 << i) {
603                 const char *name;
604                 int j;
605
606                 if (!(query.lu_types & type))
607                         continue;
608
609                 name = lfsck_type2name(type);
610                 for (j = 0; j <= LS_MAX; j++)
611                         printf("%s_mdts_%s: %d\n", name,
612                                lfsck_status2name(j), query.lu_mdts_count[i][j]);
613
614                 for (j = 0; j <= LS_MAX; j++)
615                         printf("%s_osts_%s: %d\n", name,
616                                lfsck_status2name(j), query.lu_osts_count[i][j]);
617
618                 printf("%s_repaired: %llu\n", name, query.lu_repaired[i]);
619         }
620
621         return 0;
622 }