From 8cb239805699e925dae594bc82379f0caa43b491 Mon Sep 17 00:00:00 2001 From: Jian Yu Date: Wed, 7 Feb 2018 22:45:02 -0800 Subject: [PATCH] LU-10482 flr: enhance "lfs find" to add mirror options This patch adds the following mirror related search options to "lfs find" command: [[!] --mirror-count|-N [+-]n] [[!] --mirror-state <[^]state>] --mirror-count|-N indicates mirror count. --mirror-state indicates mirrored file state. A mirrored file can be one of the following states: ro indicates the mirrored file is in read-only state. All of the mirrors contain the up-to-date data. wp indicates the mirrored file is being written. sp indicates the mirrored file is being resynchronized. Change-Id: I3c8f5c8bb6518ba4bd73fc2f164dd52afdfac211 Signed-off-by: Jian Yu Reviewed-on: https://review.whamcloud.com/31069 Tested-by: Jenkins Reviewed-by: Bobi Jam Reviewed-by: Jinshan Xiong Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/doc/lfs-find.1 | 33 +++++++++++++++++ lustre/include/lustre/lustreapi.h | 8 +++++ lustre/tests/sanity.sh | 74 ++++++++++++++++++++++++++++++++++++++ lustre/utils/lfs.c | 68 ++++++++++++++++++++++++++++++++++- lustre/utils/liblustreapi.c | 41 +++++++++++++++++++++ lustre/utils/liblustreapi_layout.c | 12 +++++++ 6 files changed, 235 insertions(+), 1 deletion(-) diff --git a/lustre/doc/lfs-find.1 b/lustre/doc/lfs-find.1 index a65a860..8ba1963 100644 --- a/lustre/doc/lfs-find.1 +++ b/lustre/doc/lfs-find.1 @@ -9,6 +9,8 @@ lfs-find \- Lustre client utility to list files with specific attributes [[\fB!\fR] \fB--component-end|\fB--comp-end\fR|\fB-E\fR [\fB+-\fR]\fIn\fR[\fBKMGTPE\fR]] [[\fB!\fR] \fB--component-flags|\fB--comp-flags\fR <[^]\fIflag\fB,\fR...>] [[\fB!\fR] \fB--component-start|\fB--comp-start\fR [\fB+-\fR]\fIn\fR[\fBKMGTPE\fR]] + [[\fB!\fR] \fB--mirror-count|\fB-N\fR [\fB+-\fR]\fIn\fR] + [[\fB!\fR] \fB--mirror-state\fR <[^]\fIstate\fR>] [[\fB!\fR] \fB--gid\fR|\fB-g\fR|\fB--group\fR|\fB-G\fR <\fIgname\fR>|<\fIgid\fR>] [[\fB!\fR] \fB--layout\fR|\fB-L mdt\fR,\fBraid0\fR,\fBreleased\fR] [\fB--maxdepth\fR|\fB-D\fI n\fR] @@ -77,10 +79,35 @@ before they can be accessed again. Replicated (mirrored) components that are preferred for read or write. For example, because they are located on SSD-based OSTs, or are more local on the network to clients. +.RE .TP .BR --component-start | --comp-start The file has component start offset \fIn\fR (in bytes) for any component. .TP +.BR --mirror-count | -N +The file has \fIn\fR mirrors in its layout. +.TP +.BR --mirror-state +The file has a state of +.I state. +If +.BI ^ state +is used, print only files not matching +.IR state. +Only one state can be specified. Valid state name is: +.RS 1.2i +.TP +.B ro +The mirrored file is in read-only state. All of the mirrors contain +the up-to-date data. +.TP +.B wp +The mirrored file is in a state of being written. +.TP +.B sp +The mirrored file is in a state of being resynchronized. +.RE +.TP .BR --gid | -g File has specified numeric group ID. .TP @@ -238,6 +265,12 @@ that have more than 3 components. .B $ lfs find --component-flags=init,prefer,^stale /mnt/lustre Recursively list all files that have at least one component with both 'init' and 'prefer' flags set, and doesn't have flag 'stale' set. +.TP +.B $ lfs find --mirror-count +2 /mnt/lustre +Recursively list all mirrored files that have more than 2 mirrors. +.TP +.B $ lfs find ! --mirror-state=ro /mnt/lustre +Recursively list all out-of-sync mirrored files. .SH BUGS The .B lfs find diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 5dec7e4..cfaeed4 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -197,6 +197,7 @@ struct find_param { fp_comp_start_sign:2, fp_comp_end_sign:2, fp_comp_count_sign:2, + fp_mirror_count_sign:2, fp_mdt_count_sign:2; unsigned long long fp_size; unsigned long long fp_size_units; @@ -232,7 +233,10 @@ struct find_param { fp_exclude_projid:1, fp_check_comp_count:1, fp_exclude_comp_count:1, + fp_check_mirror_count:1, + fp_exclude_mirror_count:1, fp_check_comp_flags:1, + fp_check_mirror_state:1, fp_check_comp_start:1, fp_exclude_comp_start:1, fp_check_comp_end:1, @@ -278,8 +282,11 @@ struct find_param { __u32 fp_layout; __u32 fp_comp_count; + __u32 fp_mirror_count; __u32 fp_comp_flags; __u32 fp_comp_neg_flags; + __u16 fp_mirror_state; + __u16 fp_mirror_neg_state; __u32 fp_comp_id; unsigned long long fp_comp_start; unsigned long long fp_comp_start_units; @@ -791,6 +798,7 @@ int llapi_layout_file_create(const char *path, int open_flags, int mode, int llapi_layout_flags_set(struct llapi_layout *layout, uint32_t flags); int llapi_layout_flags_get(struct llapi_layout *layout, uint32_t *flags); const char *llapi_layout_flags_string(uint32_t flags); +const __u16 llapi_layout_string_flags(char *string); /** * llapi_layout_mirror_count_get() - Get mirror count from the header of diff --git a/lustre/tests/sanity.sh b/lustre/tests/sanity.sh index 7d1561f..c88c65d 100755 --- a/lustre/tests/sanity.sh +++ b/lustre/tests/sanity.sh @@ -5802,6 +5802,80 @@ test_56ba() { } run_test 56ba "test lfs find --component-end, -start, -count, and -flags" +test_56ca() { + [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.10.57) ]] || + { skip "Need MDS version at least 2.10.57"; return 0; } + + local td=$DIR/$tdir + local tf=$td/$tfile + local dir + local nfiles + local cmd + local i + local j + + # create mirrored directories and mirrored files + mkdir $td || error "mkdir $td failed" + $LFS mirror create -N3 $td || error "create mirrored dir $td failed" + createmany -o $tf- 10 || error "create $tf- failed" + + for i in $(seq 2); do + dir=$td/dir$i + mkdir $dir || error "mkdir $dir failed" + $LFS mirror create -N$((3 + i)) $dir || + error "create mirrored dir $dir failed" + createmany -o $dir/$tfile- 10 || + error "create $dir/$tfile- failed" + done + + # change the states of some mirrored files + echo foo > $tf-6 + for i in $(seq 2); do + dir=$td/dir$i + for j in $(seq 4 9); do + echo foo > $dir/$tfile-$j + done + done + + # find mirrored files with specific mirror count + cmd="$LFS find --mirror-count 3 --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 10 ]] || error "$cmd: $nfiles != 10 files" + + cmd="$LFS find ! --mirror-count 3 --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 20 ]] || error "$cmd: $nfiles != 20 files" + + cmd="$LFS find --mirror-count +2 --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 30 ]] || error "$cmd: $nfiles != 30 files" + + cmd="$LFS find --mirror-count -6 --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 30 ]] || error "$cmd: $nfiles != 30 files" + + # find mirrored files with specific file state + cmd="$LFS find --maxdepth 1 --mirror-state=^ro --type f $td" + [[ $($cmd) = $tf-6 ]] || error "$cmd: didn't return $tf-6" + + cmd="$LFS find --mirror-state=ro --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 17 ]] || error "$cmd: $nfiles != 17 files" + + cmd="$LFS find ! --mirror-state=ro --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 13 ]] || error "$cmd: $nfiles != 13 files" + + cmd="$LFS find --mirror-state=wp --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 13 ]] || error "$cmd: $nfiles != 13 files" + + cmd="$LFS find ! --mirror-state=sp --type f $td" + nfiles=$($cmd | wc -l) + [[ $nfiles = 30 ]] || error "$cmd: $nfiles != 30 files" +} +run_test 56ca "check lfs find --mirror-count|-N and --mirror-state" + test_57a() { [ $PARALLEL == "yes" ] && skip "skip parallel run" && return # note test will not do anything if MDS is not local diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 1e45c0e..412cc1a 100644 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -365,6 +365,8 @@ command_t cmdlist[] = { " [[!] --component-start [+-]N[kMGTPE]]\n" " [[!] --component-end|-E [+-]N[kMGTPE]]\n" " [[!] --component-flags ]\n" + " [[!] --mirror-count|-N [+-]]\n" + " [[!] --mirror-state <[^]state>]\n" " [[!] --mdt-count|-T [+-]]\n" " [[!] --mdt-hash|-H \n" "\t !: used before an option indicates 'NOT' requested attribute\n" @@ -1105,6 +1107,30 @@ static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags) return 0; } +static int mirror_str2state(char *string, __u16 *state, __u16 *neg_state) +{ + if (string == NULL) + return -EINVAL; + + *state = 0; + *neg_state = 0; + + if (strncmp(string, "^", 1) == 0) { + *neg_state = llapi_layout_string_flags(string + 1); + if (*neg_state != 0) + return 0; + } else { + *state = llapi_layout_string_flags(string); + if (*state != 0) + return 0; + } + + llapi_printf(LLAPI_MSG_ERROR, + "%s: mirrored file state '%s' not supported\n", + progname, string); + return -EINVAL; +} + /** * struct mirror_args - Command-line arguments for mirror(s). * @m_count: Number of mirrors to be created with this layout. @@ -2262,6 +2288,7 @@ enum { LFS_PROJID_OPT, LFS_MIRROR_FLAGS_OPT, LFS_MIRROR_ID_OPT, + LFS_MIRROR_STATE_OPT, }; /* functions */ @@ -3099,6 +3126,8 @@ static int lfs_find(int argc, char **argv) { .val = LFS_COMP_START_OPT, .name = "component-start", .has_arg = required_argument }, + { .val = LFS_MIRROR_STATE_OPT, + .name = "mirror-state", .has_arg = required_argument }, { .val = 'c', .name = "stripe-count", .has_arg = required_argument }, { .val = 'c', .name = "stripe_count", .has_arg = required_argument }, { .val = 'C', .name = "ctime", .has_arg = required_argument }, @@ -3120,6 +3149,7 @@ static int lfs_find(int argc, char **argv) { .val = 'm', .name = "mdt_index", .has_arg = required_argument }, { .val = 'M', .name = "mtime", .has_arg = required_argument }, { .val = 'n', .name = "name", .has_arg = required_argument }, + { .val = 'N', .name = "mirror-count", .has_arg = required_argument }, /* find { .val = 'o' .name = "or", .has_arg = no_argument }, like find(1) */ { .val = 'O', .name = "obd", .has_arg = required_argument }, { .val = 'O', .name = "ost", .has_arg = required_argument }, @@ -3155,7 +3185,7 @@ static int lfs_find(int argc, char **argv) /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */ while ((c = getopt_long_only(argc, argv, - "-0A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v", + "-0A:c:C:D:E:g:G:H:i:L:m:M:n:N:O:Ppqrs:S:t:T:u:U:v", long_opts, NULL)) >= 0) { xtime = NULL; xsign = NULL; @@ -3269,6 +3299,23 @@ static int lfs_find(int argc, char **argv) param.fp_check_comp_start = 1; param.fp_exclude_comp_start = !!neg_opt; break; + case LFS_MIRROR_STATE_OPT: + rc = mirror_str2state(optarg, ¶m.fp_mirror_state, + ¶m.fp_mirror_neg_state); + if (rc) { + fprintf(stderr, + "error: bad mirrored file state '%s'\n", + optarg); + goto err; + } + param.fp_check_mirror_state = 1; + if (neg_opt) { + __u16 state = param.fp_mirror_neg_state; + param.fp_mirror_neg_state = + param.fp_mirror_state; + param.fp_mirror_state = state; + } + break; case 'c': if (optarg[0] == '+') { param.fp_stripe_count_sign = -1; @@ -3369,6 +3416,25 @@ static int lfs_find(int argc, char **argv) param.fp_pattern = (char *)optarg; param.fp_exclude_pattern = !!neg_opt; break; + case 'N': + if (optarg[0] == '+') { + param.fp_mirror_count_sign = -1; + optarg++; + } else if (optarg[0] == '-') { + param.fp_mirror_count_sign = 1; + optarg++; + } + + param.fp_mirror_count = strtoul(optarg, &endptr, 0); + if (*endptr != '\0') { + fprintf(stderr, + "error: bad mirror count '%s'\n", + optarg); + goto err; + } + param.fp_check_mirror_count = 1; + param.fp_exclude_mirror_count = !!neg_opt; + break; case 'm': case 'i': case 'O': { diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index e9ce5b8..ca6b732 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -3845,12 +3845,47 @@ out: return ret; } +static int find_check_mirror_options(struct find_param *param) +{ + struct lov_comp_md_v1 *comp_v1; + struct lov_user_md_v1 *v1 = ¶m->fp_lmd->lmd_lmm; + int ret = 0; + + if (v1->lmm_magic != LOV_USER_MAGIC_COMP_V1) + return -1; + + comp_v1 = (struct lov_comp_md_v1 *)v1; + + if (param->fp_check_mirror_count) { + ret = find_value_cmp(comp_v1->lcm_mirror_count + 1, + param->fp_mirror_count, + param->fp_mirror_count_sign, + param->fp_exclude_mirror_count, 1, 0); + if (ret == -1) + return ret; + } + + if (param->fp_check_mirror_state) { + ret = 1; + __u16 file_state = comp_v1->lcm_flags & LCM_FL_FLR_MASK; + + if ((param->fp_mirror_state != 0 && + file_state != param->fp_mirror_state) || + file_state == param->fp_mirror_neg_state) + return -1; + } + + return ret; +} + static bool find_check_lmm_info(struct find_param *param) { return param->fp_check_pool || param->fp_check_stripe_count || param->fp_check_stripe_size || param->fp_check_layout || param->fp_check_comp_count || param->fp_check_comp_end || param->fp_check_comp_start || param->fp_check_comp_flags || + param->fp_check_mirror_count || + param->fp_check_mirror_state || param->fp_check_projid; } @@ -4148,6 +4183,12 @@ obd_matches: goto decided; } + if (param->fp_check_mirror_count || param->fp_check_mirror_state) { + decision = find_check_mirror_options(param); + if (decision == -1) + goto decided; + } + /* Check the time on mds. */ decision = 1; if (param->fp_atime || param->fp_mtime || param->fp_ctime) { diff --git a/lustre/utils/liblustreapi_layout.c b/lustre/utils/liblustreapi_layout.c index f206c96..4b0adbd 100644 --- a/lustre/utils/liblustreapi_layout.c +++ b/lustre/utils/liblustreapi_layout.c @@ -1553,6 +1553,18 @@ const char *llapi_layout_flags_string(uint32_t flags) return "0"; } +const __u16 llapi_layout_string_flags(char *string) +{ + if (strncmp(string, "ro", strlen(string)) == 0) + return LCM_FL_RDONLY; + if (strncmp(string, "wp", strlen(string)) == 0) + return LCM_FL_WRITE_PENDING; + if (strncmp(string, "sp", strlen(string)) == 0) + return LCM_FL_SYNC_PENDING; + + return 0; +} + /** * llapi_layout_mirror_count_is_valid() - Check the validity of mirror count. * @count: Mirror count value to be checked. -- 1.8.3.1