* GPL HEADER END
*/
/*
- * Copyright (c) 2012, 2015, Intel Corporation.
+ * Copyright (c) 2012, 2016, Intel Corporation.
*/
/*
* lustre/utils/lustre_lfsck.c
#include <time.h>
#include "obdctl.h"
+#include "lustreapi_internal.h"
#include <lustre/lustre_lfsck_user.h>
#include <lnet/lnetctl.h>
-#include <lustre_ioctl.h>
+#include <linux/lustre_ioctl.h>
/* Needs to be last to avoid clashes */
#include <libcfs/util/ioctl.h>
+#include <libcfs/util/param.h>
static struct option long_opt_start[] = {
{"device", required_argument, 0, 'M'},
{"all", no_argument, 0, 'A'},
{"create_ostobj", optional_argument, 0, 'c'},
+ {"create-ostobj", optional_argument, 0, 'c'},
{"create_mdtobj", optional_argument, 0, 'C'},
+ {"create-mdtobj", optional_argument, 0, 'C'},
+ {"delay_create_ostobj", optional_argument, 0, 'd'},
+ {"delay-create-ostobj", optional_argument, 0, 'd'},
{"error", required_argument, 0, 'e'},
{"help", no_argument, 0, 'h'},
{"dryrun", optional_argument, 0, 'n'},
{"speed", required_argument, 0, 's'},
{"type", required_argument, 0, 't'},
{"window_size", required_argument, 0, 'w'},
+ {"window-size", required_argument, 0, 'w'},
{0, 0, 0, 0 }
};
static struct option long_opt_stop[] = {
- {"device", required_argument, 0, 'M'},
- {"all", no_argument, 0, 'A'},
- {"help", no_argument, 0, 'h'},
- {0, 0, 0, 0 }
-};
+ { .val = 'A', .name = "all", .has_arg = no_argument },
+ { .val = 'h', .name = "help", .has_arg = no_argument },
+ { .val = 'M', .name = "device", .has_arg = required_argument },
+ { .name = NULL } };
static struct option long_opt_query[] = {
- {"device", required_argument, 0, 'M'},
- {"type", required_argument, 0, 't'},
- {"help", no_argument, 0, 'h'},
- {"wait", no_argument, 0, 'w'},
- {0, 0, 0, 0 }
-};
+ { .val = 'h', .name = "help", .has_arg = no_argument },
+ { .val = 'M', .name = "device", .has_arg = required_argument },
+ { .val = 't', .name = "type", .has_arg = required_argument },
+ { .val = 'w', .name = "wait", .has_arg = no_argument },
+ { .name = NULL } };
struct lfsck_type_name {
char *ltn_name;
};
static struct lfsck_type_name lfsck_types_names[] = {
- { "scrub", LFSCK_TYPE_SCRUB },
- { "layout", LFSCK_TYPE_LAYOUT },
- { "namespace", LFSCK_TYPE_NAMESPACE },
- { "default", LFSCK_TYPES_DEF },
- { "all", LFSCK_TYPES_SUPPORTED },
- { NULL, 0 }
-};
+ { .ltn_name = "all", .ltn_type = LFSCK_TYPES_SUPPORTED },
+ { .ltn_name = "default", .ltn_type = LFSCK_TYPES_DEF },
+ { .ltn_name = "layout", .ltn_type = LFSCK_TYPE_LAYOUT },
+ { .ltn_name = "namespace", .ltn_type = LFSCK_TYPE_NAMESPACE },
+ { .ltn_name = "scrub", .ltn_type = LFSCK_TYPE_SCRUB },
+ { .ltn_name = NULL } };
static enum lfsck_type lfsck_name2type(const char *name)
{
{
fprintf(stderr, "start LFSCK\n"
"usage:\n"
- "lfsck_start <-M | --device {MDT,OST}_device>\n"
+ "lfsck_start [-M | --device {MDT,OST}_device]\n"
" [-A | --all] [-c | --create_ostobj [on | off]]\n"
" [-C | --create_mdtobj [on | off]]\n"
+ " [-d | --delay_create_ostobj [on | off]]\n"
" [-e | --error {continue | abort}] [-h | --help]\n"
" [-n | --dryrun [on | off]] [-o | --orphan]\n"
" [-r | --reset] [-s | --speed ops_per_sec_limit]\n"
" [-w | --window_size size]\n"
"options:\n"
"-M: device to start LFSCK/scrub on\n"
- "-A: start LFSCK on all MDT devices\n"
+ "-A: start LFSCK on all nodes via the specified MDT device "
+ "(see \"-M\" option) by single LFSCK command\n"
"-c: create the lost OST-object for dangling LOV EA "
"(default 'off', or 'on')\n"
"-C: create the lost MDT-object for dangling name entry "
"(default 'off', or 'on')\n"
+ "-d: delay create the lost OST-object for dangling LOV EA "
+ "until orphan OST-objects handled (default 'off', or 'on')\n"
"-e: error handle mode (default 'continue', or 'abort')\n"
"-h: this help message\n"
"-n: check with no modification (default 'off', or 'on')\n"
{
fprintf(stderr, "stop LFSCK\n"
"usage:\n"
- "lfsck_stop <-M | --device {MDT,OST}_device>\n"
+ "lfsck_stop [-M | --device {MDT,OST}_device]\n"
" [-A | --all] [-h | --help]\n"
"options:\n"
"-M: device to stop LFSCK/scrub on\n"
- "-A: stop LFSCK on all MDT devices\n"
+ "-A: stop LFSCK on all nodes via the specified MDT device "
+ "(see \"-M\" option) by single LFSCK command\n"
"-h: this help message\n");
}
{
fprintf(stderr, "check the LFSCK global status\n"
"usage:\n"
- "lfsck_query <-M | --device MDT_device> [-h | --help]\n"
+ "lfsck_query [-M | --device MDT_device] [-h | --help]\n"
" [-t | --type check_type[,check_type...]]\n"
" [-t | --wait]\n"
"options:\n"
return 0;
}
+static int lfsck_get_dev_name(struct obd_ioctl_data *data, char *device,
+ int types, bool multipe_devices)
+{
+ glob_t param = { 0 };
+ char *ptr;
+ int rc;
+ int i;
+
+ rc = cfs_get_param_paths(¶m, "mdd/*-MDT*");
+ if (rc) {
+ if (multipe_devices || errno != ENOENT ||
+ types & LFSCK_TYPE_NAMESPACE) {
+ fprintf(stderr, "Fail to get device name: rc = %d\n."
+ "You can specify the device explicitly "
+ "via '-M' option.\n", rc);
+ return rc;
+ }
+
+ rc = cfs_get_param_paths(¶m, "obdfilter/*-OST*");
+ if (rc) {
+ fprintf(stderr, "Fail to get device name: rc = %d\n."
+ "You can specify the device explicitly "
+ "via '-M' option.\n", rc);
+ return rc;
+ }
+ }
+
+ if (param.gl_pathc == 1)
+ goto pack;
+
+ if (!multipe_devices) {
+ fprintf(stderr,
+ "Detect multiple devices on current node. "
+ "Please specify the device explicitly "
+ "via '-M' option or '-A' option for all.\n");
+ rc = -EINVAL;
+ goto out;
+ }
+
+ ptr = strrchr(param.gl_pathv[0], '-');
+ if (ptr == NULL) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ for (i = 1; i < param.gl_pathc; i++) {
+ char *ptr2 = strrchr(param.gl_pathv[i], '-');
+
+ if (ptr2 == NULL) {
+ rc = -EINVAL;
+ goto out;
+ }
+
+ if ((ptr - param.gl_pathv[0]) != (ptr2 - param.gl_pathv[i]) ||
+ strncmp(param.gl_pathv[0], param.gl_pathv[i],
+ (ptr - param.gl_pathv[0])) != 0) {
+ fprintf(stderr,
+ "Detect multiple filesystems on current node. "
+ "Please specify the device explicitly "
+ "via '-M' option.\n");
+ rc = -EINVAL;
+ goto out;
+ }
+ }
+
+pack:
+ rc = lfsck_pack_dev(data, device, basename(param.gl_pathv[0]));
+
+out:
+ cfs_free_param_data(¶m);
+
+ return rc;
+}
+
int jt_lfsck_start(int argc, char **argv)
{
struct obd_ioctl_data data;
char rawbuf[MAX_IOC_BUFLEN], *buf = rawbuf;
char device[MAX_OBD_NAME];
struct lfsck_start start;
- char *optstring = "Ac::C::e:hM:n::ors:t:w:";
+ char *optstring = "Ac::C::d::e:hM:n::ors:t:w:";
int opt, index, rc, val, i;
memset(&data, 0, sizeof(data));
}
start.ls_valid |= LSV_CREATE_MDTOBJ;
break;
+ case 'd':
+ if (optarg == NULL || strcmp(optarg, "on") == 0) {
+ start.ls_flags |= LPF_DELAY_CREATE_OSTOBJ;
+ } else if (strcmp(optarg, "off") != 0) {
+ fprintf(stderr, "invalid switch: -c '%s'. "
+ "valid switches are:\n"
+ "empty ('on'), or 'off' without space. "
+ "For example:\n"
+ "'-c', '-con', '-coff'\n", optarg);
+ return -EINVAL;
+ }
+ start.ls_valid |= LSV_DELAY_CREATE_OSTOBJ;
+ break;
case 'e':
if (strcmp(optarg, "abort") == 0) {
start.ls_flags |= LPF_FAILOUT;
start.ls_active = LFSCK_TYPES_DEF;
if (data.ioc_inlbuf4 == NULL) {
- if (lcfg_get_devname() != NULL) {
- rc = lfsck_pack_dev(&data, device, lcfg_get_devname());
- if (rc != 0)
- return rc;
- } else {
- fprintf(stderr,
- "Must specify device to start LFSCK.\n");
- return -EINVAL;
- }
+ rc = lfsck_get_dev_name(&data, device, start.ls_active,
+ start.ls_flags & LPF_ALL_TGT);
+ if (rc != 0)
+ return rc;
}
data.ioc_inlbuf1 = (char *)&start;
}
if (data.ioc_inlbuf4 == NULL) {
- if (lcfg_get_devname() != NULL) {
- rc = lfsck_pack_dev(&data, device, lcfg_get_devname());
- if (rc != 0)
- return rc;
- } else {
- fprintf(stderr,
- "Must specify device to stop LFSCK.\n");
- return -EINVAL;
- }
+ rc = lfsck_get_dev_name(&data, device, 0,
+ stop.ls_flags & LPF_ALL_TGT);
+ if (rc != 0)
+ return rc;
}
data.ioc_inlbuf1 = (char *)&stop;
}
if (data.ioc_inlbuf4 == NULL) {
- if (lcfg_get_devname() != NULL) {
- rc = lfsck_pack_dev(&data, device, lcfg_get_devname());
- if (rc != 0)
- return rc;
- } else {
- fprintf(stderr,
- "Must specify device to query LFSCK.\n");
- return -EINVAL;
- }
+ rc = lfsck_get_dev_name(&data, device, 0, true);
+ if (rc != 0)
+ return rc;
}
data.ioc_inlbuf1 = (char *)&query;