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