Whamcloud - gitweb
b=20101
authorpanda <panda>
Wed, 2 Dec 2009 21:42:20 +0000 (21:42 +0000)
committerpanda <panda>
Wed, 2 Dec 2009 21:42:20 +0000 (21:42 +0000)
i=Andreas Dilger
i=Robert Read

a=James Simmons

Fixed lfs to maintain old behavior and support new functionality

lustre/doc/lfs.1
lustre/include/lustre/liblustreapi.h
lustre/tests/sanity.sh
lustre/utils/lfs.c
lustre/utils/liblustreapi.c

index a0a3d9b..d0e96ac 100644 (file)
@@ -24,6 +24,8 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the
 .B lfs osts
 .br
 .B lfs getstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v] 
 .B lfs osts
 .br
 .B lfs getstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v] 
+        \fB[--count | -c ] [--size | -s ] [--index | -i ]
+        \fB[--offset | -o ] [--pool | -p ] [--directory | -d ]
         \fB[--recursive|-r] <dirname|filename>\fR
 .br
 .B lfs setstripe [--size|-s stripe-size] [--count|-c stripe-cnt]
         \fB[--recursive|-r] <dirname|filename>\fR
 .br
 .B lfs setstripe [--size|-s stripe-size] [--count|-c stripe-cnt]
@@ -98,8 +100,12 @@ To search the directory tree rooted at the given dir/file name for the files tha
 .B osts 
 List all the OSTs for the filesystem
 .TP
 .B osts 
 List all the OSTs for the filesystem
 .TP
-.B getstripe
-To list the striping info for a given filename or files in a directory, optionally recursively, for all files in a directory tree: \fB--quiet\fR (don't print object IDs), \fB--verbose\fR (print striping parameters), \fB--recursive\fR (recurse into subdirectories).
+.B getstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v] 
+        \fB[--count | -c ] [--size | -s ] [--index | -i ]
+        \fB[--offset | -o ] [--pool | -p ] [--directory | -d ]
+        \fB[--recursive|-r] <dirname|filename>\fR
+.br
+To list the striping information for a given filename or directory. By default the stripe count, size, and offset will be returned. If you only want specific striping information then the options of \fB--count\fR,\fB--size\fR,\fB--index\fR or \fB--offset\fR plus various combinations of these options can be used to retrieve only what you want. What pools a file belong to can also be obtained with \fB--pool\fR. In the case where you only want details about the files object id information then the \fB--quiet\fR option is used. Additional information available about striping can be displayed with \fB--verbose\fR. The default behavior of lfs getstripe used to retrieve data about a directory is to list all the contents of that directory. If you wish to inquire only about that directory then \fB--directory\fR,can be used to list directory entries instead of its contents in the same manner as ls -d. This can be expanded with \fB--recursive\fR which will recurse into all subdirectories. You can filter the search to return only files that has a object on a specific OST with \fB--obd\fR.
 .TP
 .B setstripe [--size stripe-size] [--count stripe-cnt] 
        \fB[--offset start-ost] [--pool <pool>]\fR
 .TP
 .B setstripe [--size stripe-size] [--count stripe-cnt] 
        \fB[--offset start-ost] [--pool <pool>]\fR
@@ -198,7 +204,7 @@ Lists space usage per OST and MDT in human readable format.
 .B $ lfs df -i 
 Lists inode usage per OST and MDT
 .TP
 .B $ lfs df -i 
 Lists inode usage per OST and MDT
 .TP
-.B lfs df --pool <filesystem>[.<pool>] | <pathname>
+.B lfs df --pool <filesystem>[.<pool>] | <pathname>
 List space or inode usage for a specific OST pool
 .TP
 .B $ lfs quota -u bob /mnt/lustre
 List space or inode usage for a specific OST pool
 .TP
 .B $ lfs quota -u bob /mnt/lustre
index 20fd103..6e4ec38 100644 (file)
@@ -95,8 +95,9 @@ extern int llapi_file_lookup(int dirfd, const char *name);
 #define VERBOSE_OFFSET  0x4
 #define VERBOSE_POOL    0x8
 #define VERBOSE_DETAIL  0x10
 #define VERBOSE_OFFSET  0x4
 #define VERBOSE_POOL    0x8
 #define VERBOSE_DETAIL  0x10
+#define VERBOSE_OBJID   0x20
 #define VERBOSE_ALL     (VERBOSE_COUNT | VERBOSE_SIZE | VERBOSE_OFFSET | \
 #define VERBOSE_ALL     (VERBOSE_COUNT | VERBOSE_SIZE | VERBOSE_OFFSET | \
-                         VERBOSE_POOL)
+                         VERBOSE_POOL | VERBOSE_OBJID)
 
 struct find_param {
         unsigned int maxdepth;
 
 struct find_param {
         unsigned int maxdepth;
@@ -151,6 +152,7 @@ struct find_param {
         char poolname[LOV_MAXPOOLNAME + 1];
 };
 
         char poolname[LOV_MAXPOOLNAME + 1];
 };
 
+extern int llapi_ostlist(char *path, struct find_param *param);
 extern int llapi_uuid_match(char *real_uuid, char *search_uuid);
 extern int llapi_getstripe(char *path, struct find_param *param);
 extern int llapi_find(char *path, struct find_param *param);
 extern int llapi_uuid_match(char *real_uuid, char *search_uuid);
 extern int llapi_getstripe(char *path, struct find_param *param);
 extern int llapi_find(char *path, struct find_param *param);
index ac9f21c..45a1127 100644 (file)
@@ -1200,15 +1200,15 @@ run_test 27v "skip object creation on slow OST ================="
 test_27w() { # bug 10997
         mkdir -p $DIR/$tdir || error "mkdir failed"
         $LSTRIPE $DIR/$tdir/f0 -s 65536 || error "lstripe failed"
 test_27w() { # bug 10997
         mkdir -p $DIR/$tdir || error "mkdir failed"
         $LSTRIPE $DIR/$tdir/f0 -s 65536 || error "lstripe failed"
-        size=`$GETSTRIPE $DIR/$tdir/f0 -qs | head -n 1`
+        size=`$GETSTRIPE $DIR/$tdir/f0 -s`
         [ $size -ne 65536 ] && error "stripe size $size != 65536" || true
 
         [ "$OSTCOUNT" -lt "2" ] && skip_env "skipping multiple stripe count/offset test" && return
         for i in `seq 1 $OSTCOUNT`; do
                 offset=$(($i-1))
                 $LSTRIPE $DIR/$tdir/f$i -c $i -i $offset || error "lstripe -c $i -i $offset failed"
         [ $size -ne 65536 ] && error "stripe size $size != 65536" || true
 
         [ "$OSTCOUNT" -lt "2" ] && skip_env "skipping multiple stripe count/offset test" && return
         for i in `seq 1 $OSTCOUNT`; do
                 offset=$(($i-1))
                 $LSTRIPE $DIR/$tdir/f$i -c $i -i $offset || error "lstripe -c $i -i $offset failed"
-                count=`$GETSTRIPE -qc $DIR/$tdir/f$i | head -n 1`
-                index=`$GETSTRIPE -qo $DIR/$tdir/f$i | head -n 1`
+                count=`$GETSTRIPE -c $DIR/$tdir/f$i`
+                index=`$GETSTRIPE -o $DIR/$tdir/f$i`
                 [ $count -ne $i ] && error "stripe count $count != $i" || true
                 [ $index -ne $offset ] && error "stripe offset $index != $offset" || true
         done
                 [ $count -ne $i ] && error "stripe count $count != $i" || true
                 [ $index -ne $offset ] && error "stripe offset $index != $offset" || true
         done
@@ -2651,12 +2651,14 @@ test_56a() {    # was test_56
 
         [  "$OSTCOUNT" -lt 2 ] && \
                 skip_env "skipping other lfs getstripe --obd test" && return
 
         [  "$OSTCOUNT" -lt 2 ] && \
                 skip_env "skipping other lfs getstripe --obd test" && return
-        FILENUM=`$GETSTRIPE --recursive $DIR/d56 | sed -n '/^[  ]*1[    ]/p' | wc -l`
-        OBDUUID=`$GETSTRIPE --recursive $DIR/d56 | sed -n '/^[  ]*1:/p' | awk '{print $2}'`
-        FOUND=`$GETSTRIPE -r --obd $OBDUUID $DIR/d56 | wc -l`
+        OSTIDX=1
+        OBDUUID=$(lfs osts | grep ${OSTIDX}": " | awk '{print $2}')
+        FILENUM=`$GETSTRIPE -ir $DIR/d56 | grep -x $OSTIDX | wc -l`
+        FOUND=`$GETSTRIPE -r --obd $OBDUUID $DIR/d56 | grep obdidx | wc -l`
         [ $FOUND -eq $FILENUM ] || \
                 error "lfs getstripe --obd wrong: found $FOUND, expected $FILENUM"
         [ $FOUND -eq $FILENUM ] || \
                 error "lfs getstripe --obd wrong: found $FOUND, expected $FILENUM"
-        [ `$GETSTRIPE -r -v --obd $OBDUUID $DIR/d56 | sed '/^[  ]*1[    ]/d' |\
+        [ `$GETSTRIPE -r -v --obd $OBDUUID $DIR/d56 | \
+                sed '/^[        ]*'${OSTIDX}'[  ]/d' |\
                 sed -n '/^[     ]*[0-9][0-9]*[  ]/p' | wc -l` -eq 0 ] || \
                 error "lfs getstripe --obd wrong: should not show file on other obd"
         echo "lfs getstripe --obd passed."
                 sed -n '/^[     ]*[0-9][0-9]*[  ]/p' | wc -l` -eq 0 ] || \
                 error "lfs getstripe --obd wrong: should not show file on other obd"
         echo "lfs getstripe --obd passed."
@@ -2736,7 +2738,7 @@ run_test 56h "check lfs find ! -name ============================="
 test_56i() {
        tdir=${tdir}i
        mkdir -p $DIR/$tdir
 test_56i() {
        tdir=${tdir}i
        mkdir -p $DIR/$tdir
-       UUID=`$GETSTRIPE $DIR/$tdir | awk '/0: / { print $2 }'`
+       UUID=`$LFS osts | awk '/0: / { print $2 }'`
        OUT="`$LFIND -ost $UUID $DIR/$tdir`"
        [ "$OUT" ] && error "$LFIND returned directory '$OUT'" || true
 }
        OUT="`$LFIND -ost $UUID $DIR/$tdir`"
        [ "$OUT" ] && error "$LFIND returned directory '$OUT'" || true
 }
index 4e4228a..2457ba5 100644 (file)
@@ -133,7 +133,7 @@ command_t cmdlist[] = {
          "directory or recursively for all files in a directory tree.\n"
          "usage: getstripe [--obd|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
          "                 [--count | -c ] [--size | -s ] [--index | -i ]\n"
          "directory or recursively for all files in a directory tree.\n"
          "usage: getstripe [--obd|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
          "                 [--count | -c ] [--size | -s ] [--index | -i ]\n"
-         "                 [--offset | -o ] [--pool | -p ]\n"
+         "                 [--offset | -o ] [--pool | -p ] [--directory | -d]\n"
          "                 [--recursive | -r] <dir|file> ..."},
         {"pool_list", lfs_poollist, 0,
          "List pools or pool OSTs\n"
          "                 [--recursive | -r] <dir|file> ..."},
         {"pool_list", lfs_poollist, 0,
          "List pools or pool OSTs\n"
@@ -824,14 +824,15 @@ static int lfs_getstripe(int argc, char **argv)
                 {"offset", 0, 0, 'o'},
                 {"pool", 0, 0, 'p'},
                 {"verbose", 0, 0, 'v'},
                 {"offset", 0, 0, 'o'},
                 {"pool", 0, 0, 'p'},
                 {"verbose", 0, 0, 'v'},
+                {"directory", 0, 0, 'd'},
                 {0, 0, 0, 0}
         };
                 {0, 0, 0, 0}
         };
-        char short_opts[] = "hO:qrvcsiop";
         int c, rc;
         struct find_param param = { 0 };
 
         int c, rc;
         struct find_param param = { 0 };
 
+        param.maxdepth = 1;
         optind = 0;
         optind = 0;
-        while ((c = getopt_long(argc, argv, short_opts,
+        while ((c = getopt_long(argc, argv, "cdhioO:pqrsv",
                                 long_opts, NULL)) != -1) {
                 switch (c) {
                 case 'O':
                                 long_opts, NULL)) != -1) {
                 switch (c) {
                 case 'O':
@@ -846,22 +847,33 @@ static int lfs_getstripe(int argc, char **argv)
                 case 'q':
                         param.quiet++;
                         break;
                 case 'q':
                         param.quiet++;
                         break;
+                case 'd':
+                        param.maxdepth = 0;
+                        break;
                 case 'r':
                         param.recursive = 1;
                         break;
                 case 'v':
                         param.verbose = VERBOSE_ALL | VERBOSE_DETAIL;
                 case 'r':
                         param.recursive = 1;
                         break;
                 case 'v':
                         param.verbose = VERBOSE_ALL | VERBOSE_DETAIL;
-                        param.quiet = 0;
                         break;
                 case 'c':
                         break;
                 case 'c':
-                        param.verbose |= VERBOSE_COUNT;
+                        if (!(param.verbose & VERBOSE_DETAIL)) {
+                                param.verbose |= VERBOSE_COUNT;
+                                param.maxdepth = 0;
+                        }
                         break;
                 case 's':
                         break;
                 case 's':
-                        param.verbose |= VERBOSE_SIZE;
+                        if (!(param.verbose & VERBOSE_DETAIL)) {
+                                param.verbose |= VERBOSE_SIZE;
+                                param.maxdepth = 0;
+                        }
                         break;
                 case 'i':
                 case 'o':
                         break;
                 case 'i':
                 case 'o':
-                        param.verbose |= VERBOSE_OFFSET;
+                        if (!(param.verbose & VERBOSE_DETAIL)) {
+                                param.verbose |= VERBOSE_OFFSET;
+                                param.maxdepth = 0;
+                        }
                         break;
                 case 'p':
                         param.verbose |= VERBOSE_POOL;
                         break;
                 case 'p':
                         param.verbose |= VERBOSE_POOL;
@@ -878,7 +890,13 @@ static int lfs_getstripe(int argc, char **argv)
         if (optind >= argc)
                 return CMD_HELP;
 
         if (optind >= argc)
                 return CMD_HELP;
 
-        param.maxdepth = param.recursive ? -1 : 1;
+        if (param.recursive)
+                param.maxdepth = -1;
+
+        if (!param.verbose)
+                param.verbose = VERBOSE_ALL;
+        if (param.quiet)
+                param.verbose = VERBOSE_OBJID;
 
         do {
                 rc = llapi_getstripe(argv[optind], &param);
 
         do {
                 rc = llapi_getstripe(argv[optind], &param);
@@ -901,7 +919,7 @@ static int lfs_osts(int argc, char **argv)
 
         while (llapi_search_mounts(NULL, index++, mntdir, NULL) == 0) {
                 memset(&param, 0, sizeof(param));
 
         while (llapi_search_mounts(NULL, index++, mntdir, NULL) == 0) {
                 memset(&param, 0, sizeof(param));
-                rc = llapi_getstripe(mntdir, &param);
+                rc = llapi_ostlist(mntdir, &param);
                 if (rc) {
                         fprintf(stderr, "error: %s: failed on %s\n",
                                 argv[0], mntdir);
                 if (rc) {
                         fprintf(stderr, "error: %s: failed on %s\n",
                                 argv[0], mntdir);
index d97c676..b62736b 100644 (file)
@@ -897,6 +897,205 @@ static void find_param_fini(struct find_param *param)
                 free(param->lmd);
 }
 
                 free(param->lmd);
 }
 
+static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
+                          cfs_dirent_t *de)
+{
+        struct find_param *param = (struct find_param *)data;
+        param->depth--;
+        return 0;
+}
+
+static DIR *opendir_parent(char *path)
+{
+        DIR *parent;
+        char *fname;
+        char c;
+
+        fname = strrchr(path, '/');
+        if (fname == NULL)
+                return opendir(".");
+
+        c = fname[1];
+        fname[1] = '\0';
+        parent = opendir(path);
+        fname[1] = c;
+        return parent;
+}
+
+int llapi_mds_getfileinfo(char *path, DIR *parent,
+                          struct lov_user_mds_data *lmd)
+{
+        lstat_t *st = &lmd->lmd_st;
+        char *fname = strrchr(path, '/');
+        int ret = 0;
+
+        if (parent == NULL)
+                return -EINVAL;
+
+        fname = (fname == NULL ? path : fname + 1);
+        /* retrieve needed file info */
+        strncpy((char *)lmd, fname,
+                lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC));
+        ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
+
+        if (ret) {
+                if (errno == ENOTTY) {
+                        /* ioctl is not supported, it is not a lustre fs.
+                         * Do the regular lstat(2) instead. */
+                        ret = lstat_f(path, st);
+                        if (ret) {
+                                llapi_err(LLAPI_MSG_ERROR,
+                                          "error: %s: lstat failed for %s",
+                                          __FUNCTION__, path);
+                                return ret;
+                        }
+                } else if (errno == ENOENT) {
+                        llapi_err(LLAPI_MSG_WARN,
+                                  "warning: %s: %s does not exist",
+                                  __FUNCTION__, path);
+                        return -ENOENT;
+                } else {
+                        llapi_err(LLAPI_MSG_ERROR,
+                                 "error: %s: IOC_MDC_GETFILEINFO failed for %s",
+                                 __FUNCTION__, path);
+                        return ret;
+                }
+        }
+
+        return 0;
+}
+
+static int llapi_semantic_traverse(char *path, int size, DIR *parent,
+                                   semantic_func_t sem_init,
+                                   semantic_func_t sem_fini, void *data,
+                                   cfs_dirent_t *de)
+{
+        cfs_dirent_t *dent;
+        int len, ret;
+        DIR *d, *p = NULL;
+
+        ret = 0;
+        len = strlen(path);
+
+        d = opendir(path);
+        if (!d && errno != ENOTDIR) {
+                llapi_err(LLAPI_MSG_ERROR, "%s: Failed to open '%s'",
+                          __FUNCTION__, path);
+                return -EINVAL;
+        } else if (!d && !parent) {
+                /* ENOTDIR. Open the parent dir. */
+                p = opendir_parent(path);
+                if (!p)
+                        GOTO(out, ret = -EINVAL);
+        }
+
+        if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
+                goto err;
+
+        if (!d)
+                GOTO(out, ret = 0);
+
+        while ((dent = readdir64(d)) != NULL) {
+                ((struct find_param *)data)->have_fileinfo = 0;
+
+                if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                        continue;
+
+                /* Don't traverse .lustre directory */
+                if (!(strcmp(dent->d_name, dot_lustre_name)))
+                        continue;
+
+                path[len] = 0;
+                if ((len + dent->d_reclen + 2) > size) {
+                        llapi_err(LLAPI_MSG_ERROR,
+                                  "error: %s: string buffer is too small",
+                                  __FUNCTION__);
+                        break;
+                }
+                strcat(path, "/");
+                strcat(path, dent->d_name);
+
+                if (dent->d_type == DT_UNKNOWN) {
+                        lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
+
+                        ret = llapi_mds_getfileinfo(path, d,
+                                             ((struct find_param *)data)->lmd);
+                        if (ret == 0) {
+                                ((struct find_param *)data)->have_fileinfo = 1;
+                                dent->d_type =
+                                        llapi_filetype_dir_table[st->st_mode &
+                                                                 S_IFMT];
+                        }
+                        if (ret == -ENOENT)
+                                continue;
+                }
+
+                switch (dent->d_type) {
+                case DT_UNKNOWN:
+                        llapi_err(LLAPI_MSG_ERROR,
+                                  "error: %s: '%s' is UNKNOWN type %d",
+                                  __FUNCTION__, dent->d_name, dent->d_type);
+                        break;
+                case DT_DIR:
+                        ret = llapi_semantic_traverse(path, size, d, sem_init,
+                                                      sem_fini, data, dent);
+                        if (ret < 0)
+                                goto out;
+                        break;
+                default:
+                        ret = 0;
+                        if (sem_init) {
+                                ret = sem_init(path, d, NULL, data, dent);
+                                if (ret < 0)
+                                        goto out;
+                        }
+                        if (sem_fini && ret == 0)
+                                sem_fini(path, d, NULL, data, dent);
+                }
+        }
+
+out:
+        path[len] = 0;
+
+        if (sem_fini)
+                sem_fini(path, parent, d, data, de);
+err:
+        if (d)
+                closedir(d);
+        if (p)
+                closedir(p);
+        return ret;
+}
+
+static int param_callback(char *path, semantic_func_t sem_init,
+                          semantic_func_t sem_fini, struct find_param *param)
+{
+        int ret, len = strlen(path);
+        char *buf;
+
+        if (len > PATH_MAX) {
+                llapi_err(LLAPI_MSG_ERROR, "Path name '%s' is too long", path);
+                return -EINVAL;
+        }
+
+        buf = (char *)malloc(PATH_MAX + 1);
+        if (!buf)
+                return -ENOMEM;
+
+        ret = common_param_init(param);
+        if (ret)
+                goto out;
+        param->depth = 0;
+
+        strncpy(buf, path, PATH_MAX + 1);
+        ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, sem_init,
+                                      sem_fini, param, NULL);
+out:
+        find_param_fini(param);
+        free(buf);
+        return ret < 0 ? ret : 0;
+}
+
 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
 {
         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
 {
         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
@@ -1016,6 +1215,9 @@ static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
         FILE *fp;
         int rc = 0, index;
 
         FILE *fp;
         int rc = 0, index;
 
+        if (param->got_uuids)
+                return rc;
+
         /* Get the lov name */
         rc = llapi_file_fget_lov_uuid(dirfd(dir), &lov_uuid);
         if (rc) {
         /* Get the lov name */
         rc = llapi_file_fget_lov_uuid(dirfd(dir), &lov_uuid);
         if (rc) {
@@ -1062,8 +1264,7 @@ static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
 
         fclose(fp);
 
 
         fclose(fp);
 
-        if (!param->quiet && param->obduuid &&
-            (param->obdindex == OBD_NOT_FOUND)) {
+        if (param->obduuid && (param->obdindex == OBD_NOT_FOUND)) {
                 llapi_err_noerrno(LLAPI_MSG_ERROR,
                                   "error: %s: unknown obduuid: %s",
                                   __FUNCTION__, param->obduuid->uuid);
                 llapi_err_noerrno(LLAPI_MSG_ERROR,
                                   "error: %s: unknown obduuid: %s",
                                   __FUNCTION__, param->obduuid->uuid);
@@ -1139,14 +1340,36 @@ retry_get_uuids:
         return ret;
 }
 
         return ret;
 }
 
+static int cb_ostlist(char *path, DIR *parent, DIR *d, void *data,
+                      struct dirent64 *de)
+{
+        struct find_param *param = (struct find_param *)data;
+
+        LASSERT(parent != NULL || d != NULL);
+
+        /* Prepare odb. */
+        return setup_obd_uuid(d ? d : parent, path, param);
+}
+
+int llapi_ostlist(char *path, struct find_param *param)
+{
+        return param_callback(path, cb_ostlist, cb_common_fini, param);
+}
+
 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
-                                     int is_dir, int verbose, int quiet,
+                                     int is_dir, int verbose, int depth,
                                      char *pool_name)
 {
         char *prefix = is_dir ? "" : "lmm_";
         char nl = is_dir ? ' ' : '\n';
 
                                      char *pool_name)
 {
         char *prefix = is_dir ? "" : "lmm_";
         char nl = is_dir ? ' ' : '\n';
 
-        if (verbose && path)
+        if (is_dir && lum->lmm_object_gr == LOV_OBJECT_GROUP_DEFAULT) {
+                lum->lmm_object_gr = LOV_OBJECT_GROUP_CLEAR;
+                if (verbose & VERBOSE_DETAIL)
+                        llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
+        }
+
+        if (depth && path && ((verbose != VERBOSE_OBJID) || !is_dir))
                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
 
         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
 
         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
@@ -1159,7 +1382,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
         }
 
         if (verbose & VERBOSE_COUNT) {
         }
 
         if (verbose & VERBOSE_COUNT) {
-                if (!quiet)
+                if (verbose & ~VERBOSE_COUNT)
                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count:   ",
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%hd%c",
                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count:   ",
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%hd%c",
@@ -1167,7 +1390,7 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
         }
 
         if (verbose & VERBOSE_SIZE) {
         }
 
         if (verbose & VERBOSE_SIZE) {
-                if (!quiet)
+                if (verbose & ~VERBOSE_SIZE)
                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size:    ",
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size,
                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size:    ",
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size,
@@ -1180,63 +1403,44 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
         }
 
         if (verbose & VERBOSE_OFFSET) {
         }
 
         if (verbose & VERBOSE_OFFSET) {
-                if (!quiet)
-                        llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset:   ",
+                if (verbose & ~VERBOSE_OFFSET)
+                        llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset:  ",
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c",
                              lum->lmm_objects[0].l_ost_idx, nl);
         }
 
                                      prefix);
                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c",
                              lum->lmm_objects[0].l_ost_idx, nl);
         }
 
-        if ((verbose & VERBOSE_POOL) && (pool_name != NULL))
-                llapi_printf(LLAPI_MSG_NORMAL, "pool: %s%c", pool_name, nl);
+        if ((verbose & VERBOSE_POOL) && (pool_name != NULL)) {
+                llapi_printf(LLAPI_MSG_NORMAL, "pool: %s", pool_name);
+                is_dir = 1;
+        }
 
 
-        if (is_dir)
+        if (is_dir && (verbose != VERBOSE_OBJID))
                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
 }
 
 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
                             struct lov_user_ost_data_v1 *objects,
                             char *path, int is_dir,
                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
 }
 
 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
                             struct lov_user_ost_data_v1 *objects,
                             char *path, int is_dir,
-                            int obdindex, int quiet, int header, int body)
+                            int obdindex, int depth, int header)
 {
 {
-        int i, obdstripe = 0;
+        int i, obdstripe = (obdindex != OBD_NOT_FOUND) ? 0 : 1;
 
 
-        if (obdindex != OBD_NOT_FOUND) {
+        if (!obdstripe) {
                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
                         if (obdindex == objects[i].l_ost_idx) {
                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
                         if (obdindex == objects[i].l_ost_idx) {
-                                llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
                                 obdstripe = 1;
                                 break;
                         }
                 }
                                 obdstripe = 1;
                                 break;
                         }
                 }
-        } else {
-                if (!quiet)
-                        llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
-                obdstripe = 1;
-        }
-
-        /* if it's a directory */
-        if (is_dir) {
-                if (obdstripe == 1) {
-                        if (lum->lmm_object_gr == LOV_OBJECT_GROUP_DEFAULT) {
-                                llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
-                                lum->lmm_object_gr = LOV_OBJECT_GROUP_CLEAR;
-                        }
-                        /* maintain original behavior */
-                        if (!header)
-                                header |= VERBOSE_ALL;
-                        lov_dump_user_lmm_header(lum, path, is_dir, header,
-                                                 quiet, pool_name);
-                }
-                return;
         }
 
         }
 
-        if (header && (obdstripe == 1))
-                lov_dump_user_lmm_header(lum, NULL, is_dir, header, quiet,
+        if (obdstripe == 1)
+                lov_dump_user_lmm_header(lum, path, is_dir, header, depth,
                                          pool_name);
 
                                          pool_name);
 
-        if (body) {
-                if ((!quiet) && (obdstripe == 1))
+        if (!is_dir && (header & VERBOSE_OBJID)) {
+                if (obdstripe == 1)
                         llapi_printf(LLAPI_MSG_NORMAL,
                                      "\tobdidx\t\t objid\t\tobjid\t\t group\n");
 
                         llapi_printf(LLAPI_MSG_NORMAL,
                                      "\tobdidx\t\t objid\t\tobjid\t\t group\n");
 
@@ -1262,9 +1466,8 @@ void llapi_lov_dump_user_lmm(struct find_param *param,
                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
                                        param->lmd->lmd_lmm.lmm_objects,
                                        path, is_dir,
                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
                                        param->lmd->lmd_lmm.lmm_objects,
                                        path, is_dir,
-                                       param->obdindex, param->quiet,
-                                       param->verbose,
-                                       (param->verbose || !param->obduuid));
+                                       param->obdindex, param->maxdepth,
+                                       param->verbose);
                 break;
         case LOV_USER_MAGIC_V3: {
                 char pool_name[LOV_MAXPOOLNAME + 1];
                 break;
         case LOV_USER_MAGIC_V3: {
                 char pool_name[LOV_MAXPOOLNAME + 1];
@@ -1276,9 +1479,8 @@ void llapi_lov_dump_user_lmm(struct find_param *param,
                 objects = lmmv3->lmm_objects;
                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
                                        objects, path, is_dir,
                 objects = lmmv3->lmm_objects;
                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
                                        objects, path, is_dir,
-                                       param->obdindex, param->quiet,
-                                       param->verbose,
-                                       (param->verbose || !param->obduuid));
+                                       param->obdindex, param->maxdepth,
+                                       param->verbose);
                 break;
         }
         default:
                 break;
         }
         default:
@@ -1358,168 +1560,6 @@ int llapi_file_lookup(int dirfd, const char *name)
         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
 }
 
         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
 }
 
-int llapi_mds_getfileinfo(char *path, DIR *parent,
-                          struct lov_user_mds_data *lmd)
-{
-        lstat_t *st = &lmd->lmd_st;
-        char *fname = strrchr(path, '/');
-        int ret = 0;
-
-        if (parent == NULL)
-                return -EINVAL;
-
-        fname = (fname == NULL ? path : fname + 1);
-        /* retrieve needed file info */
-        strncpy((char *)lmd, fname,
-                lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC));
-        ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
-
-        if (ret) {
-                if (errno == ENOTTY) {
-                        /* ioctl is not supported, it is not a lustre fs.
-                         * Do the regular lstat(2) instead. */
-                        ret = lstat_f(path, st);
-                        if (ret) {
-                                llapi_err(LLAPI_MSG_ERROR,
-                                          "error: %s: lstat failed for %s",
-                                          __FUNCTION__, path);
-                                return ret;
-                        }
-                } else if (errno == ENOENT) {
-                        llapi_err(LLAPI_MSG_WARN,
-                                  "warning: %s: %s does not exist",
-                                  __FUNCTION__, path);
-                        return -ENOENT;
-                } else {
-                        llapi_err(LLAPI_MSG_ERROR,
-                                 "error: %s: IOC_MDC_GETFILEINFO failed for %s",
-                                 __FUNCTION__, path);
-                        return ret;
-                }
-        }
-
-        return 0;
-}
-
-static DIR *opendir_parent(char *path)
-{
-        DIR *parent;
-        char *fname;
-        char c;
-
-        fname = strrchr(path, '/');
-        if (fname == NULL)
-                return opendir(".");
-
-        c = fname[1];
-        fname[1] = '\0';
-        parent = opendir(path);
-        fname[1] = c;
-        return parent;
-}
-
-static int llapi_semantic_traverse(char *path, int size, DIR *parent,
-                                   semantic_func_t sem_init,
-                                   semantic_func_t sem_fini, void *data,
-                                   cfs_dirent_t *de)
-{
-        cfs_dirent_t *dent;
-        int len, ret;
-        DIR *d, *p = NULL;
-
-        ret = 0;
-        len = strlen(path);
-
-        d = opendir(path);
-        if (!d && errno != ENOTDIR) {
-                llapi_err(LLAPI_MSG_ERROR, "%s: Failed to open '%s'",
-                          __FUNCTION__, path);
-                return -EINVAL;
-        } else if (!d && !parent) {
-                /* ENOTDIR. Open the parent dir. */
-                p = opendir_parent(path);
-                if (!p)
-                        GOTO(out, ret = -EINVAL);
-        }
-
-        if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
-                goto err;
-
-        if (!d)
-                GOTO(out, ret = 0);
-
-        while ((dent = readdir64(d)) != NULL) {
-                ((struct find_param *)data)->have_fileinfo = 0;
-
-                if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
-                        continue;
-
-                /* Don't traverse .lustre directory */
-                if (!(strcmp(dent->d_name, dot_lustre_name)))
-                        continue;
-
-                path[len] = 0;
-                if ((len + dent->d_reclen + 2) > size) {
-                        llapi_err(LLAPI_MSG_ERROR,
-                                  "error: %s: string buffer is too small",
-                                  __FUNCTION__);
-                        break;
-                }
-                strcat(path, "/");
-                strcat(path, dent->d_name);
-
-                if (dent->d_type == DT_UNKNOWN) {
-                        lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
-
-                        ret = llapi_mds_getfileinfo(path, d,
-                                             ((struct find_param *)data)->lmd);
-                        if (ret == 0) {
-                                ((struct find_param *)data)->have_fileinfo = 1;
-                                dent->d_type =
-                                        llapi_filetype_dir_table[st->st_mode &
-                                                                 S_IFMT];
-                        }
-                        if (ret == -ENOENT)
-                                continue;
-                }
-
-                switch (dent->d_type) {
-                case DT_UNKNOWN:
-                        llapi_err(LLAPI_MSG_ERROR,
-                                  "error: %s: '%s' is UNKNOWN type %d",
-                                  __FUNCTION__, dent->d_name, dent->d_type);
-                        break;
-                case DT_DIR:
-                        ret = llapi_semantic_traverse(path, size, d, sem_init,
-                                                      sem_fini, data, dent);
-                        if (ret < 0)
-                                goto out;
-                        break;
-                default:
-                        ret = 0;
-                        if (sem_init) {
-                                ret = sem_init(path, d, NULL, data, dent);
-                                if (ret < 0)
-                                        goto out;
-                        }
-                        if (sem_fini && ret == 0)
-                                sem_fini(path, d, NULL, data, dent);
-                }
-        }
-
-out:
-        path[len] = 0;
-
-        if (sem_fini)
-                sem_fini(path, parent, d, data, de);
-err:
-        if (d)
-                closedir(d);
-        if (p)
-                closedir(p);
-        return ret;
-}
-
 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
  *
 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
  *
@@ -1902,44 +1942,9 @@ decided:
         return 0;
 }
 
         return 0;
 }
 
-static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
-                          cfs_dirent_t *de)
-{
-        struct find_param *param = (struct find_param *)data;
-        param->depth--;
-        return 0;
-}
-
 int llapi_find(char *path, struct find_param *param)
 {
 int llapi_find(char *path, struct find_param *param)
 {
-        char *buf;
-        int ret, len = strlen(path);
-
-        if (len > PATH_MAX) {
-                llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
-                          __FUNCTION__, path);
-                return -EINVAL;
-        }
-
-        buf = (char *)malloc(PATH_MAX + 1);
-        if (!buf)
-                return -ENOMEM;
-
-        ret = common_param_init(param);
-        if (ret) {
-                free(buf);
-                return ret;
-        }
-
-        param->depth = 0;
-
-        strncpy(buf, path, PATH_MAX + 1);
-        ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init,
-                                      cb_common_fini, param, NULL);
-
-        find_param_fini(param);
-        free(buf);
-        return ret < 0 ? ret : 0;
+        return param_callback(path, cb_find_init, cb_common_fini, param);        
 }
 
 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
 }
 
 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
@@ -1950,8 +1955,8 @@ static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
 
         LASSERT(parent != NULL || d != NULL);
 
 
         LASSERT(parent != NULL || d != NULL);
 
-        /* Prepare odb. */
-        if (!param->got_uuids) {
+        if (param->obduuid) {
+                param->quiet = 1;
                 ret = setup_obd_uuid(d ? d : parent, path, param);
                 if (ret)
                         return ret;
                 ret = setup_obd_uuid(d ? d : parent, path, param);
                 if (ret)
                         return ret;
@@ -1971,7 +1976,7 @@ static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
 
         if (ret) {
                 if (errno == ENODATA) {
 
         if (ret) {
                 if (errno == ENODATA) {
-                        if (!param->obduuid && !param->quiet)
+                        if (!param->obduuid)
                                 llapi_printf(LLAPI_MSG_NORMAL,
                                              "%s has no stripe info\n", path);
                         goto out;
                                 llapi_printf(LLAPI_MSG_NORMAL,
                                              "%s has no stripe info\n", path);
                         goto out;
@@ -2006,34 +2011,7 @@ out:
 
 int llapi_getstripe(char *path, struct find_param *param)
 {
 
 int llapi_getstripe(char *path, struct find_param *param)
 {
-        char *buf;
-        int ret = 0, len = strlen(path);
-
-        if (len > PATH_MAX) {
-                llapi_err(LLAPI_MSG_ERROR,
-                          "%s: Path name '%s' is too long",
-                          __FUNCTION__, path);
-                return -EINVAL;
-        }
-
-        buf = (char *)malloc(PATH_MAX + 1);
-        if (!buf)
-                return -ENOMEM;
-
-        ret = common_param_init(param);
-        if (ret) {
-                free(buf);
-                return ret;
-        }
-
-        param->depth = 0;
-
-        strncpy(buf, path, PATH_MAX + 1);
-        ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe,
-                                      cb_common_fini, param, NULL);
-        find_param_fini(param);
-        free(buf);
-        return ret < 0 ? ret : 0;
+        return param_callback(path, cb_getstripe, cb_common_fini, param);
 }
 
 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
 }
 
 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
@@ -2350,35 +2328,13 @@ static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
 int llapi_quotachown(char *path, int flag)
 {
         struct find_param param;
 int llapi_quotachown(char *path, int flag)
 {
         struct find_param param;
-        char *buf;
-        int ret = 0, len = strlen(path);
-
-        if (len > PATH_MAX) {
-                llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
-                          __FUNCTION__, path);
-                return -EINVAL;
-        }
-
-        buf = (char *)malloc(PATH_MAX + 1);
-        if (!buf)
-                return -ENOMEM;
 
         memset(&param, 0, sizeof(param));
         param.recursive = 1;
         param.verbose = 0;
         param.quiet = 1;
 
 
         memset(&param, 0, sizeof(param));
         param.recursive = 1;
         param.verbose = 0;
         param.quiet = 1;
 
-        ret = common_param_init(&param);
-        if (ret)
-                goto out;
-
-        strncpy(buf, path, PATH_MAX + 1);
-        ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown,
-                                      NULL, &param, NULL);
-out:
-        find_param_fini(&param);
-        free(buf);
-        return ret;
+        return param_callback(path, cb_quotachown, NULL, &param);
 }
 
 #include <pwd.h>
 }
 
 #include <pwd.h>