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