Whamcloud - gitweb
LU-10522 utils: new --mindepth for lfs find 26/55226/14
authorMaximilian Dilger <mdilger@whamcloud.com>
Tue, 28 May 2024 17:55:27 +0000 (13:55 -0400)
committerOleg Drokin <green@whamcloud.com>
Mon, 8 Jul 2024 20:11:07 +0000 (20:11 +0000)
Added [--mindepth | -d] option for 'lfs find' to print
only the results found after N levels. Similar usage to existing
mindepth found in find.

Signed-off-by: Maximilian Dilger <mdilger@whamcloud.com>
Change-Id: I7816e27355f6796edc8437f700342da1b7e564d0
Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55226
Reviewed-by: Andreas Dilger <adilger@whamcloud.com>
Reviewed-by: Jian Yu <yujian@whamcloud.com>
Reviewed-by: Oleg Drokin <green@whamcloud.com>
Tested-by: jenkins <devops@whamcloud.com>
Tested-by: Maloo <maloo@whamcloud.com>
lustre/doc/lfs-find.1
lustre/doc/lfs.1
lustre/include/lustre/lustreapi.h
lustre/tests/sanity.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c

index 9a9a6ba..09a1bbc 100644 (file)
@@ -18,7 +18,7 @@ lfs-find \- Lustre client utility to list files with specific attributes
       [\fB--help\fR|\fB-h\fR]
 [[\fB!\fR] \fB--layout\fR|\fB-L mdt\fR,\fBraid0\fR,\fBreleased\fR]
 [\fB--lazy|-l\fR]
-      [[\fB!\fR] \fB--links\fR [\fB+-\fR]\fIn\fR] [\fB--maxdepth\fR|\fB-D\fI n\fR]
+      [[\fB!\fR] \fB--links\fR [\fB+-\fR]\fIn\fR] [\fB--maxdepth\fR|\fB-D\fI n\fR] [\fB--mindepth\fR|\fB-d\fI n\fR]
       [[\fB!\fR] \fB--mdt\fR|\fB--mdt-index\fR|\fB-m\fR \fIUUID\fR|\fIINDEX\fR,...]
       [[\fB!\fR] \fB--mdt-count\fR|\fB-T\fR [\fB+-\fR]\fIn\fR]
 [[\fB!\fR] \fB--mdt-hash\fR|\fB-H \fR<[^]\fIHASHFLAG\fR,[^]\fIHASHTYPE\fR,...>]
@@ -174,6 +174,9 @@ File has \fIn\fR links.
 .BR --maxdepth
 Limits find to decend at most \fIn\fR levels of directory tree.
 .TP
+.BR --mindepth
+Starts find at \fIn\fR levels of directory tree.
+.TP
 .BR --mdt | --mdt-index | -m
 File or directory inode is located on the specified MDT(s).
 .TP
index 7746b82..de7ab1d 100644 (file)
@@ -27,7 +27,7 @@ lfs \- client utility for Lustre-specific file layout and other attributes
       [[\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--maxdepth\fR|\fB-D\fI n\fR] [\fB--mindepth\fR|\fB-d\fI n\fR]
       [[\fB!\fR] \fB--mdt\fR|\fB--mdt-index\fR|\fB-m\fR <\fIuuid\fR|\fIindex\fR,...>]
       [[\fB!\fR] \fB--mdt-count\fR|\fB-T\fR [\fB+-\fR]\fIn\fR]
 [[\fB!\fR] \fB--mdt-hash\fR|\fB-H \fI<hashtype>\fR]
index 5be8c33..5b7bb4a 100644 (file)
@@ -268,6 +268,7 @@ struct xattr_match_info {
  */
 struct find_param {
        unsigned int             fp_max_depth;
+       unsigned int             fp_min_depth;
        dev_t                    fp_dev;
        mode_t                   fp_type; /* S_IFIFO,... */
        uid_t                    fp_uid;
index 83bb14a..1a08b90 100755 (executable)
@@ -9040,6 +9040,26 @@ test_56dc() {
 }
 run_test 56dc "test 'lfs df -o' only shows OST devices"
 
+test_56dd() {
+       local dir=$DIR/d$(basetest $testnum)g.$TESTSUITE
+
+       setup_56 $dir $NUMFILES $NUMDIRS
+
+       local lfscount=($($LFS find $dir -mindepth 1 -maxdepth 2 | sort))
+       local findcount=($(find $dir -mindepth 1 -maxdepth 2 | sort))
+
+       if [[ ${#lfscount[@]} != ${#findcount[@]} ]]; then
+               error "lfs find returned ${#lfscount[@]} files, find returned ${#findcount[@]} files"
+       fi
+
+       for ((i = 0; i < ${#lfscount[@]}; i++)); do
+               [[ "${lfscount[$i]}" == "${findcount[$i]}" ]] &&
+                       echo "${lfscount[$i]}" ||
+                       error "${#lfscount[@]} != ${#findcount[@]}"
+       done
+}
+run_test 56dd "test lfs find with mindepth argument"
+
 test_56ea() { #LU-10378
        local path=$DIR/$tdir
        local pool=$TESTNAME
index 24a50ec..f779290 100755 (executable)
@@ -391,7 +391,8 @@ command_t cmdlist[] = {
         "     [[!] --foreign[=<foreign_type>]]\n"
         "     [[!] --gid|-g|--group|-G <gid>|<gname>] [--help|-h]\n"
         "     [[!] --layout|-L released,raid0,mdt] [--lazy|-l] [[!] --links [+-]n]\n"
-        "     [--maxdepth|-D N] [[!] --mdt-count|-T [+-]<stripes>]\n"
+        "     [--maxdepth|-D N] [--mindepth|-d N]\n"
+        "     [[!] --mdt-count|-T [+-]<stripes>]\n"
         "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
         "     [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
         "     [[!] --mirror-count|-N [+-]<n>]\n"
@@ -5321,6 +5322,7 @@ static int lfs_find(int argc, char **argv)
        time_t t;
        struct find_param param = {
                .fp_max_depth = -1,
+               .fp_min_depth = 0,
                .fp_quiet = 1,
                .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
        };
@@ -5404,6 +5406,7 @@ static int lfs_find(int argc, char **argv)
        { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
        { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
 /* getstripe { .val = 'd', .name = "directory",        .has_arg = no_argument }, */
+       { .val = 'd',   .name = "mindepth",     .has_arg = required_argument },
        { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
        { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
        { .val = 'E',   .name = "component-end",
@@ -5475,7 +5478,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:b:B:c:C:D:E:g:G:hH:i:k:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
+               "-0A:b:B:c:C:d:D:E:g:G:hH:i:k:lL:m:M:n:N:O:Ppqrs:S:t:T:u:U:z:",
                long_opts, &optidx)) >= 0) {
                xtime = NULL;
                xsign = NULL;
@@ -5676,6 +5679,17 @@ static int lfs_find(int argc, char **argv)
                        param.fp_check_stripe_count = 1;
                        param.fp_exclude_stripe_count = !!neg_opt;
                        break;
+               case 'd':
+                       errno = 0;
+                       param.fp_min_depth = strtoul(optarg, 0, 0);
+                       if (errno != 0 || param.fp_min_depth > PATH_MAX / 2) {
+                               fprintf(stderr,
+                                       "error: bad mindepth '%s'\n",
+                                       optarg);
+                               ret = -1;
+                               goto err;
+                       }
+                       break;
                case 'D':
                        errno = 0;
                        param.fp_max_depth = strtol(optarg, 0, 0);
@@ -6281,6 +6295,13 @@ err_free:
                pathend = argc;
        }
 
+       if (param.fp_min_depth > param.fp_max_depth) {
+               fprintf(stderr, "error: %s: mindepth %u > maxdepth %u\n",
+                       argv[0], param.fp_min_depth, param.fp_max_depth);
+               ret = CMD_HELP;
+               goto err;
+       }
+
        do {
                rc = llapi_find(argv[pathstart], &param);
                if (rc) {
index 2693b3e..d46da02 100644 (file)
@@ -2022,6 +2022,7 @@ static int llapi_semantic_traverse(char *path, int size, int parent,
                                          __func__, dent->d_name, dent->d_type);
                        break;
                case DT_DIR:
+                       /* recursion down into a new subdirectory here */
                        rc = llapi_semantic_traverse(path, size, d, sem_init,
                                                     sem_fini, data, dent);
                        if (rc != 0 && ret == 0)
@@ -5575,6 +5576,9 @@ static int cb_find_init(char *path, int p, int *dp,
 
        if (p == -1 && d == -1)
                return -EINVAL;
+       /* if below minimum depth do not process further */
+       if (param->fp_depth < param->fp_min_depth)
+               goto decided;
 
        /* Reset this value between invocations */
        param->fp_get_lmv = 0;
@@ -6121,6 +6125,7 @@ print:
                llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path,
                             param->fp_zero_end ? '\0' : '\n');
 
+
 decided:
        ret = 0;
        /* Do not get down anymore? */