Whamcloud - gitweb
LU-15220 utils: fix gcc-11 -Werror=format-truncation= error
[fs/lustre-release.git] / lustre / utils / liblustreapi.c
index 2d29c35..ca5debe 100644 (file)
@@ -400,9 +400,54 @@ int llapi_ioctl_unpack(struct obd_ioctl_data *data, char *pbuf, int max_len)
 
 /* XXX: llapi_xxx() functions return negative values upon failure */
 
-int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset,
-                               int stripe_count, int stripe_pattern)
+int llapi_layout_search_ost(__u32 ost, char *pname, char *fsname)
 {
+       char ostname[MAX_OBD_NAME + 64];
+       char *pool_name = pname;
+       int rc = 0;
+
+       /**
+        * The current policy is that the pool does not have to exist at the
+        * setstripe time, see sanity-pfl/-flr tests.
+        * If this logic will change, re-enable it.
+        *
+        * if (pname && strlen(pname) == 0)
+        */
+               pool_name = NULL;
+
+       snprintf(ostname, sizeof(ostname), "%s-OST%04x_UUID",
+                fsname, ost);
+       rc = llapi_search_ost(fsname, pool_name, ostname);
+       if (rc <= 0) {
+               if (rc == 0)
+                       rc = -ENODEV;
+
+               llapi_error(LLAPI_MSG_ERROR, rc,
+                           "%s: cannot find OST %s in %s", __func__, ostname,
+                           pool_name != NULL ? "pool" : "system");
+               return rc;
+       }
+
+       return 0;
+}
+
+/**
+ * Verify the setstripe parameters before using.
+ * This is a pair method for comp_args_to_layout()/llapi_layout_sanity_cb()
+ * when just 1 component or a non-PFL layout is given.
+ *
+ * \param[in] param            stripe parameters
+ * \param[in] pool_name                pool name
+ * \param[in] fsname           lustre FS name
+ *
+ * \retval                     0, success
+ *                             < 0, error code on failre
+ */
+static int llapi_stripe_param_verify(const struct llapi_stripe_param *param,
+                                    char **pool_name,
+                                    char *fsname)
+{
+       int count;
        static int page_size;
        int rc = 0;
 
@@ -420,33 +465,94 @@ int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset,
                                          page_size, LOV_MIN_STRIPE_SIZE);
                }
        }
-       if (!llapi_stripe_size_is_aligned(stripe_size)) {
+       if (!llapi_stripe_size_is_aligned(param->lsp_stripe_size)) {
                rc = -EINVAL;
                llapi_error(LLAPI_MSG_ERROR, rc,
                            "error: bad stripe_size %llu, must be an even multiple of %d bytes",
-                           (unsigned long long)stripe_size, page_size);
+                           param->lsp_stripe_size, page_size);
                goto out;
        }
-       if (!llapi_stripe_index_is_valid(stripe_offset)) {
+       if (!llapi_stripe_index_is_valid(param->lsp_stripe_offset)) {
                rc = -EINVAL;
                llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
-                               stripe_offset);
+                           param->lsp_stripe_offset);
                goto out;
        }
-       if (!llapi_stripe_count_is_valid(stripe_count)) {
+       if (llapi_stripe_size_is_too_big(param->lsp_stripe_size)) {
                rc = -EINVAL;
-               llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
-                               stripe_count);
+               llapi_error(LLAPI_MSG_ERROR, rc,
+                           "error: stripe size '%llu' over 4GB limit",
+                           param->lsp_stripe_size);
                goto out;
        }
-       if (llapi_stripe_size_is_too_big(stripe_size)) {
+
+       count = param->lsp_stripe_count;
+       if (param->lsp_stripe_pattern == LOV_PATTERN_MDT) {
                rc = -EINVAL;
                llapi_error(LLAPI_MSG_ERROR, rc,
-                           "error: stripe size '%llu' over 4GB limit",
-                           (unsigned long long)stripe_size);
+                           "Invalid pattern: %d, must be specified with -E\n",
+                           param->lsp_stripe_pattern);
                goto out;
+       } else {
+               if (!llapi_stripe_count_is_valid(count)) {
+                       rc = -EINVAL;
+                       llapi_error(LLAPI_MSG_ERROR, rc,
+                                   "Invalid stripe count %d\n", count);
+                       goto out;
+               }
+       }
+
+       /* Make sure we have a good pool */
+       if (*pool_name != NULL) {
+               if (!llapi_pool_name_is_valid(pool_name, fsname)) {
+                       rc = -EINVAL;
+                       llapi_error(LLAPI_MSG_ERROR, rc,
+                                   "Pool '%s' is not on filesystem '%s'",
+                                   *pool_name, fsname);
+                       goto out;
+               }
+
+               /* Make sure the pool exists and is non-empty */
+               rc = llapi_search_ost(fsname, *pool_name, NULL);
+               if (rc < 1) {
+                       char *err = rc == 0 ? "has no OSTs" : "does not exist";
+
+                       rc = -EINVAL;
+                       llapi_error(LLAPI_MSG_ERROR, rc, "pool '%s.%s' %s",
+                                   fsname, *pool_name, err);
+                       goto out;
+               }
+               rc = 0;
        }
 
+       /* sanity check of target list */
+       if (param->lsp_is_specific) {
+               bool found = false;
+               int i;
+
+               for (i = 0; i < count; i++) {
+                       rc = llapi_layout_search_ost(param->lsp_osts[i],
+                                                    *pool_name, fsname);
+                       if (rc)
+                               goto out;
+
+                       /* Make sure stripe offset is in OST list. */
+                       if (param->lsp_osts[i] == param->lsp_stripe_offset)
+                               found = true;
+               }
+               if (!found) {
+                       rc = -EINVAL;
+                       llapi_error(LLAPI_MSG_ERROR, rc,
+                                   "%s: stripe offset '%d' is not in the target list",
+                                   __func__, param->lsp_stripe_offset);
+                       goto out;
+               }
+       } else if (param->lsp_stripe_offset != -1) {
+               rc = llapi_layout_search_ost(param->lsp_stripe_offset,
+                                            *pool_name, fsname);
+               if (rc)
+                       goto out;
+       }
 out:
        errno = -rc;
        return rc;
@@ -570,9 +676,9 @@ int llapi_file_open_param(const char *name, int flags, mode_t mode,
                          const struct llapi_stripe_param *param)
 {
        char fsname[MAX_OBD_NAME + 1] = { 0 };
-       char *pool_name = param->lsp_pool;
        struct lov_user_md *lum = NULL;
-       size_t lum_size = sizeof(*lum);
+       char *pool_name = param->lsp_pool;
+       size_t lum_size;
        int fd, rc;
 
        /* Make sure we are on a Lustre file system */
@@ -585,82 +691,17 @@ int llapi_file_open_param(const char *name, int flags, mode_t mode,
        }
 
        /* Check if the stripe pattern is sane. */
-       rc = llapi_stripe_limit_check(param->lsp_stripe_size,
-                                     param->lsp_stripe_offset,
-                                     param->lsp_stripe_count,
-                                     param->lsp_stripe_pattern);
+       rc = llapi_stripe_param_verify(param, &pool_name, fsname);
        if (rc != 0)
                return rc;
 
-       /* Make sure we have a good pool */
-       if (pool_name != NULL) {
-               /*
-                * in case user gives the full pool name <fsname>.<poolname>,
-                * strip the fsname
-                */
-               char *ptr = strchr(pool_name, '.');
-
-               if (ptr != NULL) {
-                       *ptr = '\0';
-                       if (strcmp(pool_name, fsname) != 0) {
-                               *ptr = '.';
-                               llapi_err_noerrno(LLAPI_MSG_ERROR,
-                                       "Pool '%s' is not on filesystem '%s'",
-                                       pool_name, fsname);
-                               return -EINVAL;
-                       }
-                       pool_name = ptr + 1;
-               }
-
-               /* Make sure the pool exists and is non-empty */
-               rc = llapi_search_ost(fsname, pool_name, NULL);
-               if (rc < 1) {
-                       char *err = rc == 0 ? "has no OSTs" : "does not exist";
-
-                       llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
-                                         fsname, pool_name, err);
-                       return -EINVAL;
-               }
-
-               lum_size = sizeof(struct lov_user_md_v3);
-       }
-
-       /* sanity check of target list */
-       if (param->lsp_is_specific) {
-               char ostname[MAX_OBD_NAME + 64];
-               bool found = false;
-               int i;
-
-               for (i = 0; i < param->lsp_stripe_count; i++) {
-                       snprintf(ostname, sizeof(ostname), "%s-OST%04x_UUID",
-                                fsname, param->lsp_osts[i]);
-                       rc = llapi_search_ost(fsname, pool_name, ostname);
-                       if (rc <= 0) {
-                               if (rc == 0)
-                                       rc = -ENODEV;
-
-                               llapi_error(LLAPI_MSG_ERROR, rc,
-                                           "%s: cannot find OST %s in %s",
-                                           __func__, ostname,
-                                           pool_name != NULL ?
-                                           "pool" : "system");
-                               return rc;
-                       }
-
-                       /* Make sure stripe offset is in OST list. */
-                       if (param->lsp_osts[i] == param->lsp_stripe_offset)
-                               found = true;
-               }
-               if (!found) {
-                       llapi_error(LLAPI_MSG_ERROR, -EINVAL,
-                                   "%s: stripe offset '%d' is not in the target list",
-                                   __func__, param->lsp_stripe_offset);
-                       return -EINVAL;
-               }
-
+       if (param->lsp_is_specific)
                lum_size = lov_user_md_size(param->lsp_stripe_count,
                                            LOV_USER_MAGIC_SPECIFIC);
-       }
+       else if (pool_name)
+               lum_size = sizeof(struct lov_user_md_v3);
+       else
+               lum_size = sizeof(*lum);
 
        lum = calloc(1, lum_size);
        if (lum == NULL)
@@ -735,6 +776,18 @@ retry_open:
        return fd;
 }
 
+int llapi_file_is_encrypted(int fd)
+{
+       unsigned long flags;
+       int rc;
+
+       rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
+       if (rc == -1)
+               return -errno;
+
+       return !!(flags & LUSTRE_ENCRYPT_FL);
+}
+
 int llapi_file_open_pool(const char *name, int flags, int mode,
                         unsigned long long stripe_size, int stripe_offset,
                         int stripe_count, int stripe_pattern, char *pool_name)
@@ -1658,6 +1711,34 @@ free_path:
 /* wrapper for lfs.c and obd.c */
 int llapi_poollist(const char *name)
 {
+       int poolcount, rc, i;
+       char *buf, **pools;
+
+       rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount);
+       if (rc)
+               return rc;
+
+       for (i = 0; i < poolcount; i++)
+               llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]);
+       free(buf);
+
+       return 0;
+}
+
+/**
+ * Get buffer that holds uuids and the list of pools in a filesystem.
+ *
+ * \param name         filesystem name or path
+ * \param buf          bufffer that has to be freed if function returns 0
+ * \param pools                pointer to the list of pools in buffer
+ * \param poolcount    number of pools
+ *
+ * \return 0 when found at least 1 pool, i.e. poolcount  > 0
+ * \retval -error failure
+ */
+int llapi_get_poolbuf(const char *name, char **buf,
+                     char ***pools, int *poolcount)
+{
        /*
         * list of pool names (assume that pool count is smaller
         * than OST count)
@@ -1665,7 +1746,7 @@ int llapi_poollist(const char *name)
        char **list, *buffer = NULL, *fsname = (char *)name;
        char *poolname = NULL, *tmp = NULL, data[16];
        enum param_filter type = FILTER_BY_PATH;
-       int obdcount, bufsize, rc, nb, i;
+       int obdcount, bufsize, rc, nb;
 
        if (name == NULL)
                return -EINVAL;
@@ -1717,11 +1798,15 @@ retry_get_pools:
                goto retry_get_pools;
        }
 
-       for (i = 0; i < nb; i++)
-               llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]);
        rc = (nb < 0 ? nb : 0);
+       if (!rc) {
+               *buf = buffer;
+               *pools = list;
+               *poolcount = nb;
+       }
 err:
-       if (buffer)
+       /* Don't free buffer, it will be used later */
+       if (rc && buffer)
                free(buffer);
        if (fsname != NULL && type == FILTER_BY_FS_NAME)
                free(fsname);
@@ -1733,6 +1818,11 @@ typedef int (semantic_func_t)(char *path, int p, int *d,
 
 #define OBD_NOT_FOUND           (-1)
 
+static bool lmv_is_foreign(__u32 magic)
+{
+       return magic == LMV_MAGIC_FOREIGN;
+}
+
 static void find_param_fini(struct find_param *param)
 {
        if (param->fp_migrate)
@@ -1830,6 +1920,8 @@ static int cb_get_dirstripe(char *path, int *d, struct find_param *param)
        int ret;
        bool did_nofollow = false;
 
+       if (!d || *d < 0)
+               return -ENOTDIR;
 again:
        param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count;
        if (param->fp_get_default_lmv)
@@ -1872,7 +1964,7 @@ again:
                int lmv_size;
 
                /* if foreign LMV case, fake stripes number */
-               if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) {
+               if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) {
                        struct lmv_foreign_md *lfm;
 
                        lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
@@ -1908,6 +2000,7 @@ again:
                }
                goto again;
        }
+
        return ret;
 }
 
@@ -2878,7 +2971,8 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
                             space, prefix,
                             (uintmax_t)lmm_oi_id(&lum->lmm_oi));
        }
-       if ((verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) && !is_dir) {
+
+       if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
                __u64 seq;
                __u32 oid;
                __u32 ver;
@@ -2886,30 +2980,51 @@ static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
                if (verbose & ~VERBOSE_DFID)
                        llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid:           ",
                                     space);
-               /*
-                * This needs a bit of hand-holding since old 1.x lmm_oi
-                * have { oi.oi_id = mds_inum, oi.oi_seq = 0 } and 2.x lmm_oi
-                * have { oi.oi_id = mds_oid, oi.oi_seq = mds_seq } instead of
-                * a real FID.  Ideally the 2.x code would have stored this
-                * like a FID with { oi_id = mds_seq, oi_seq = mds_oid } so the
-                * ostid union lu_fid { f_seq = mds_seq, f_oid = mds_oid }
-                * worked properly (especially since IGIF FIDs use mds_inum as
-                * the FID SEQ), but unfortunately that didn't happen.
-                *
-                * Print it to look like an IGIF FID, even though the fields
-                * are reversed on disk, so that it makes sense to userspace.
-                *
-                * Don't use ostid_id() and ostid_seq(), since they assume the
-                * oi_fid fields are in the right order.  This is why there are
-                * separate lmm_oi_seq() and lmm_oi_id() routines for this.
-                *
-                * For newer layout types hopefully this will be a real FID.
-                */
-               seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
-                       lmm_oi_id(&lum->lmm_oi) : lmm_oi_seq(&lum->lmm_oi);
-               oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
-                       0 : (__u32)lmm_oi_id(&lum->lmm_oi);
-               ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
+
+               if (is_dir) {
+                       struct lu_fid dir_fid;
+
+                       rc = llapi_path2fid(path, &dir_fid);
+                       if (rc)
+                               llapi_error(LLAPI_MSG_ERROR, rc,
+                                           "Cannot determine directory fid.");
+
+                       seq = dir_fid.f_seq;
+                       oid = dir_fid.f_oid;
+                       ver = dir_fid.f_ver;
+               } else {
+                       /*
+                        * This needs a bit of hand-holding since old 1.x
+                        * lmm_oi have { oi.oi_id = mds_inum, oi.oi_seq = 0 }
+                        * and 2.x lmm_oi have { oi.oi_id = mds_oid,
+                        * oi.oi_seq = mds_seq } instead of a real FID.
+                        * Ideally the 2.x code would have stored this like a
+                        * FID with { oi_id = mds_seq, oi_seq = mds_oid } so
+                        * the ostid union lu_fid { f_seq = mds_seq,
+                        * f_oid = mds_oid } worked properly (especially since
+                        * IGIF FIDs use mds_inum as the FID SEQ), but
+                        * unfortunately that didn't happen.
+                        *
+                        * Print it to look like an IGIF FID, even though the
+                        * fields are reversed on disk, so that it makes sense
+                        * to userspace.
+                        *
+                        * Don't use ostid_id() and ostid_seq(), since they
+                        * assume the oi_fid fields are in the right order.
+                        * This is why there are separate lmm_oi_seq() and
+                        * lmm_oi_id() routines for this.
+                        *
+                        * For newer layout types hopefully this will be a
+                        * real FID.
+                        */
+                       seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
+                               lmm_oi_id(&lum->lmm_oi) :
+                               lmm_oi_seq(&lum->lmm_oi);
+                       oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
+                           0 : (__u32)lmm_oi_id(&lum->lmm_oi);
+                       ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
+               }
+
                if (yaml)
                        llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n",
                                     (unsigned long long)seq, oid, ver);
@@ -3216,6 +3331,11 @@ void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
                        llapi_printf(LLAPI_MSG_NORMAL, ",bad_type");
                if (flags & LMV_HASH_FLAG_LOST_LMV)
                        llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv");
+               if (flags & LMV_HASH_FLAG_FIXED)
+                       llapi_printf(LLAPI_MSG_NORMAL, ",fixed");
+               if (flags & ~LMV_HASH_FLAG_KNOWN)
+                       llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x",
+                                    flags & ~LMV_HASH_FLAG_KNOWN);
 
                if (verbose & VERBOSE_HASH_TYPE && !yaml)
                        separator = " ";
@@ -3550,7 +3670,7 @@ static inline void
 lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
 {
        if (v1->lmm_magic == LOV_USER_MAGIC_V3)
-               snprintf(pool_name, LOV_MAXPOOLNAME, "%s",
+               snprintf(pool_name, LOV_MAXPOOLNAME + 1, "%s",
                         ((struct lov_user_md_v3 *)v1)->lmm_pool_name);
        else
                pool_name[0] = '\0';
@@ -4051,7 +4171,7 @@ static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
        }
 }
 
-int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
+static int llapi_file_get_stripe1(const char *path, struct lov_user_md *lum)
 {
        const char *fname;
        char *dname;
@@ -4093,6 +4213,31 @@ out_free:
        return rc;
 }
 
+int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
+{
+       char *canon_path = NULL;
+       int rc, rc2;
+
+       rc = llapi_file_get_stripe1(path, lum);
+       if (!(rc == -ENOTTY || rc == -ENODATA))
+               goto out;
+
+       /* Handle failure due to symlinks by dereferencing path manually. */
+       canon_path = canonicalize_file_name(path);
+       if (canon_path == NULL)
+               goto out; /* Keep original rc. */
+
+       rc2 = llapi_file_get_stripe1(canon_path, lum);
+       if (rc2 < 0)
+               goto out; /* Keep original rc. */
+
+       rc = 0;
+out:
+       free(canon_path);
+
+       return rc;
+}
+
 int llapi_file_lookup(int dirfd, const char *name)
 {
        struct obd_ioctl_data data = { 0 };
@@ -4537,7 +4682,7 @@ static int find_check_foreign(struct find_param *param)
                struct lmv_foreign_md *lfm;
 
                lfm = (void *)param->fp_lmv_md;
-               if (lfm->lfm_magic != LMV_MAGIC_FOREIGN) {
+               if (lmv_is_foreign(lfm->lfm_magic)) {
                        if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
                                return param->fp_exclude_foreign ? 1 : -1;
                        return -1;
@@ -4743,6 +4888,35 @@ static int fget_projid(int fd, int *projid)
        return 0;
 }
 
+/*
+ * Check that the file's permissions in *st matches the one in find_param
+ */
+static int check_file_permissions(const struct find_param *param,
+                       mode_t mode)
+{
+       int decision = 0;
+
+       mode &= 07777;
+
+       switch (param->fp_perm_sign) {
+       case LFS_FIND_PERM_EXACT:
+               decision = (mode == param->fp_perm);
+               break;
+       case LFS_FIND_PERM_ALL:
+               decision = ((mode & param->fp_perm) == param->fp_perm);
+               break;
+       case LFS_FIND_PERM_ANY:
+               decision = ((mode & param->fp_perm) != 0);
+               break;
+       }
+
+       if ((param->fp_exclude_perm && decision)
+               || (!param->fp_exclude_perm && !decision))
+               return -1;
+       else
+               return 1;
+}
+
 static int cb_find_init(char *path, int p, int *dp,
                        void *data, struct dirent64 *de)
 {
@@ -4772,16 +4946,21 @@ static int cb_find_init(char *path, int p, int *dp,
        }
 
        /* See if we can check the file type from the dirent. */
-       if (param->fp_type != 0 && de != NULL && de->d_type != DT_UNKNOWN) {
-               checked_type = 1;
+       if (de != NULL && de->d_type != DT_UNKNOWN) {
+               if (param->fp_type != 0) {
+                       checked_type = 1;
 
-               if (DTTOIF(de->d_type) == param->fp_type) {
-                       if (param->fp_exclude_type)
-                               goto decided;
-               } else {
-                       if (!param->fp_exclude_type)
-                               goto decided;
+                       if (DTTOIF(de->d_type) == param->fp_type) {
+                               if (param->fp_exclude_type)
+                                       goto decided;
+                       } else {
+                               if (!param->fp_exclude_type)
+                                       goto decided;
+                       }
                }
+               if ((param->fp_check_mdt_count || param->fp_hash_type ||
+                    param->fp_check_hash_flag) && de->d_type != DT_DIR)
+                       goto decided;
        }
 
        ret = 0;
@@ -4797,30 +4976,73 @@ static int cb_find_init(char *path, int p, int *dp,
            param->fp_check_size || param->fp_check_blocks ||
            find_check_lmm_info(param) ||
            param->fp_check_mdt_count || param->fp_hash_type ||
-           param->fp_check_hash_flag)
+           param->fp_check_hash_flag || param->fp_perm_sign)
                decision = 0;
 
        if (param->fp_type != 0 && checked_type == 0)
                decision = 0;
 
        if (decision == 0) {
-               if (d != -1 && (param->fp_check_mdt_count ||
-                   param->fp_hash_type || param->fp_check_foreign ||
-                   param->fp_check_hash_flag)) {
+               if (d != -1 &&
+                   (param->fp_check_mdt_count || param->fp_hash_type ||
+                    param->fp_check_hash_flag || param->fp_check_foreign)) {
                        param->fp_get_lmv = 1;
                        ret = cb_get_dirstripe(path, &d, param);
                        if (ret != 0) {
-                               /*
-                                * XXX this works to decide for foreign
-                                * criterion only
-                                */
-                               if (errno == ENODATA &&
-                                   param->fp_check_foreign) {
-                                       if (param->fp_exclude_foreign)
-                                               goto foreign;
-                                       goto decided;
+                               if (errno == ENODATA) {
+                                       ret = 0;
+                                       if (param->fp_check_mdt_count ||
+                                           param->fp_hash_type ||
+                                           param->fp_check_hash_flag) {
+                                               param->fp_lmv_md->lum_stripe_count = 0;
+                                               param->fp_lmv_md->lum_hash_type = 0;
+                                       }
+                                       if (param->fp_check_foreign) {
+                                               if (param->fp_exclude_foreign)
+                                                       goto print;
+                                               goto decided;
+                                       }
+                               } else {
+                                       return ret;
                                }
-                               return ret;
+                       }
+
+                       if (param->fp_check_mdt_count) {
+                               if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
+                                       goto decided;
+
+                               decision = find_value_cmp(param->fp_lmv_md->lum_stripe_count,
+                                                         param->fp_mdt_count,
+                                                         param->fp_mdt_count_sign,
+                                                         param->fp_exclude_mdt_count, 1, 0);
+                               if (decision == -1)
+                                       goto decided;
+                       }
+
+                       if (param->fp_hash_type) {
+                               __u32 found;
+                               __u32 type = param->fp_lmv_md->lum_hash_type &
+                                       LMV_HASH_TYPE_MASK;
+
+                               if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
+                                       goto decided;
+
+                               found = (1 << type) & param->fp_hash_type;
+                               if ((found && param->fp_exclude_hash_type) ||
+                                   (!found && !param->fp_exclude_hash_type))
+                                       goto decided;
+                       }
+
+                       if (param->fp_check_hash_flag) {
+                               __u32 flags = param->fp_lmv_md->lum_hash_type &
+                                       ~LMV_HASH_TYPE_MASK;
+
+                               if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
+                                       goto decided;
+
+                               if (!(flags & param->fp_hash_inflags) ||
+                                   (flags & param->fp_hash_exflags))
+                                       goto decided;
                        }
                }
 
@@ -4885,7 +5107,18 @@ static int cb_find_init(char *path, int p, int *dp,
                }
        }
 
+       /* Check the file permissions from the stat info */
+       if (param->fp_perm_sign) {
+               decision = check_file_permissions(param, lmd->lmd_stx.stx_mode);
+               if (decision == -1)
+                       goto decided;
+       }
+
        if (param->fp_type && !checked_type) {
+               if ((param->fp_check_mdt_count || param->fp_check_hash_flag ||
+                    param->fp_hash_type) && !S_ISDIR(lmd->lmd_stx.stx_mode))
+                       goto decided;
+
                if ((lmd->lmd_stx.stx_mode & S_IFMT) == param->fp_type) {
                        if (param->fp_exclude_type)
                                goto decided;
@@ -4949,61 +5182,12 @@ static int cb_find_init(char *path, int p, int *dp,
                        goto decided;
        }
 
-       if (param->fp_check_mdt_count) {
-               if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) {
-                       decision = -1;
-                       goto decided;
-               }
-
-               decision = find_value_cmp(
-                               param->fp_lmv_md->lum_stripe_count,
-                               param->fp_mdt_count,
-                               param->fp_mdt_count_sign,
-                               param->fp_exclude_mdt_count, 1, 0);
-               if (decision == -1)
-                       goto decided;
-       }
-
        if (param->fp_check_layout) {
                decision = find_check_layout(param);
                if (decision == -1)
                        goto decided;
        }
 
-       if (param->fp_hash_type) {
-               __u32 found;
-               __u32 type = param->fp_lmv_md->lum_hash_type &
-                            LMV_HASH_TYPE_MASK;
-
-               if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) {
-                       decision = -1;
-                       goto decided;
-               }
-
-               found = (1 << type) & param->fp_hash_type;
-               if ((found && param->fp_exclude_hash_type) ||
-                   (!found && !param->fp_exclude_hash_type)) {
-                       decision = -1;
-                       goto decided;
-               }
-       }
-
-       if (param->fp_check_hash_flag) {
-               __u32 flags = param->fp_lmv_md->lum_hash_type &
-                             ~LMV_HASH_TYPE_MASK;
-
-               if (param->fp_lmv_md->lum_magic == LMV_MAGIC_FOREIGN) {
-                       decision = -1;
-                       goto decided;
-               }
-
-               if (!(flags & param->fp_hash_inflags) ||
-                    (flags & param->fp_hash_exflags)) {
-                       decision = -1;
-                       goto decided;
-               }
-       }
-
        /* If an OBD UUID is specified but none matches, skip this file. */
        if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) ||
            (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND))
@@ -5230,12 +5414,9 @@ obd_matches:
                        goto decided;
        }
 
-foreign:
-       llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
-       if (param->fp_zero_end)
-               llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
-       else
-               llapi_printf(LLAPI_MSG_NORMAL, "\n");
+print:
+       llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path,
+                    param->fp_zero_end ? '\0' : '\n');
 
 decided:
        ret = 0;
@@ -5293,6 +5474,9 @@ static int cb_migrate_mdt_init(char *path, int p, int *dp,
        data.ioc_inlbuf2 = (char *)lmu;
        data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count,
                                            lmu->lum_magic);
+       /* reach bottom? */
+       if (param->fp_depth == param->fp_max_depth)
+               data.ioc_type = MDS_MIGRATE_NSONLY;
        ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
        if (ret != 0) {
                llapi_error(LLAPI_MSG_ERROR, ret,
@@ -5334,6 +5518,11 @@ migrate:
        }
 
 out:
+       /* Do not get down anymore? */
+       if (param->fp_depth == param->fp_max_depth)
+               ret = 1;
+       param->fp_depth++;
+
        if (dp != NULL) {
                /*
                 * If the directory is being migration, we need