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