Whamcloud - gitweb
LU-10482 flr: enhance "lfs find" to add mirror options 69/31069/6
authorJian Yu <jian.yu@intel.com>
Thu, 8 Feb 2018 06:45:02 +0000 (22:45 -0800)
committerOleg Drokin <oleg.drokin@intel.com>
Wed, 14 Feb 2018 00:52:47 +0000 (00:52 +0000)
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 <jian.yu@intel.com>
Reviewed-on: https://review.whamcloud.com/31069
Tested-by: Jenkins
Reviewed-by: Bobi Jam <bobijam@hotmail.com>
Reviewed-by: Jinshan Xiong <jinshan.xiong@intel.com>
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
lustre/doc/lfs-find.1
lustre/include/lustre/lustreapi.h
lustre/tests/sanity.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/liblustreapi_layout.c

index a65a860..8ba1963 100644 (file)
@@ -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--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]
       [[\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.
 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
 .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
 .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.
 .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
 .SH BUGS
 The
 .B lfs find
index 5dec7e4..cfaeed4 100644 (file)
@@ -197,6 +197,7 @@ struct find_param {
                                 fp_comp_start_sign:2,
                                 fp_comp_end_sign:2,
                                 fp_comp_count_sign:2,
                                 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;
                                 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_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_comp_flags:1,
+                                fp_check_mirror_state:1,
                                 fp_check_comp_start:1,
                                 fp_exclude_comp_start:1,
                                 fp_check_comp_end: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_layout;
 
        __u32                    fp_comp_count;
+       __u32                    fp_mirror_count;
        __u32                    fp_comp_flags;
        __u32                    fp_comp_neg_flags;
        __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;
        __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);
 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
 
 /**
  * llapi_layout_mirror_count_get() - Get mirror count from the header of
index 7d1561f..c88c65d 100755 (executable)
@@ -5802,6 +5802,80 @@ test_56ba() {
 }
 run_test 56ba "test lfs find --component-end, -start, -count, and -flags"
 
 }
 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
 test_57a() {
        [ $PARALLEL == "yes" ] && skip "skip parallel run" && return
        # note test will not do anything if MDS is not local
index 1e45c0e..412cc1a 100644 (file)
@@ -365,6 +365,8 @@ command_t cmdlist[] = {
         "     [[!] --component-start [+-]N[kMGTPE]]\n"
         "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
         "     [[!] --component-flags <comp_flags>]\n"
         "     [[!] --component-start [+-]N[kMGTPE]]\n"
         "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
         "     [[!] --component-flags <comp_flags>]\n"
+        "     [[!] --mirror-count|-N [+-]<n>]\n"
+        "     [[!] --mirror-state <[^]state>]\n"
         "     [[!] --mdt-count|-T [+-]<stripes>]\n"
         "     [[!] --mdt-hash|-H <hashtype>\n"
          "\t !: used before an option indicates 'NOT' requested attribute\n"
         "     [[!] --mdt-count|-T [+-]<stripes>]\n"
         "     [[!] --mdt-hash|-H <hashtype>\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;
 }
 
        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.
 /**
  * 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_PROJID_OPT,
        LFS_MIRROR_FLAGS_OPT,
        LFS_MIRROR_ID_OPT,
+       LFS_MIRROR_STATE_OPT,
 };
 
 /* functions */
 };
 
 /* 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_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 },
        { .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 = '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 },
 /* 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,
 
        /* 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;
                        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;
                        param.fp_check_comp_start = 1;
                        param.fp_exclude_comp_start = !!neg_opt;
                        break;
+               case LFS_MIRROR_STATE_OPT:
+                       rc = mirror_str2state(optarg, &param.fp_mirror_state,
+                                             &param.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;
                 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;
                        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': {
                 case 'm':
                 case 'i':
                 case 'O': {
index e9ce5b8..ca6b732 100644 (file)
@@ -3845,12 +3845,47 @@ out:
        return ret;
 }
 
        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 = &param->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 ||
 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;
 }
 
               param->fp_check_projid;
 }
 
@@ -4148,6 +4183,12 @@ obd_matches:
                        goto decided;
        }
 
                        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) {
        /* Check the time on mds. */
        decision = 1;
        if (param->fp_atime || param->fp_mtime || param->fp_ctime) {
index f206c96..4b0adbd 100644 (file)
@@ -1553,6 +1553,18 @@ const char *llapi_layout_flags_string(uint32_t flags)
        return "0";
 }
 
        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.
 /**
  * llapi_layout_mirror_count_is_valid() - Check the validity of mirror count.
  * @count: Mirror count value to be checked.