Whamcloud - gitweb
LU-15220 utils: fix gcc-11 -Werror=format-truncation= error
[fs/lustre-release.git] / lustre / utils / liblustreapi.c
index 0f85d29..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)
@@ -962,6 +1015,8 @@ static inline void param2lmu(struct lmv_user_md *lmu,
        lmu->lum_stripe_count = param->lsp_stripe_count;
        lmu->lum_stripe_offset = param->lsp_stripe_offset;
        lmu->lum_hash_type = param->lsp_stripe_pattern;
+       lmu->lum_max_inherit = param->lsp_max_inherit;
+       lmu->lum_max_inherit_rr = param->lsp_max_inherit_rr;
        if (param->lsp_pool != NULL)
                strncpy(lmu->lum_pool_name, param->lsp_pool, LOV_MAXPOOLNAME);
        if (param->lsp_is_specific) {
@@ -1086,6 +1141,9 @@ int llapi_dir_create(const char *name, mode_t mode,
        data.ioc_inlbuf2 = (char *)lmu;
        data.ioc_inllen2 = lmu_size;
        data.ioc_type = mode;
+       if (param->lsp_is_create)
+               /* borrow obdo1.o_flags to store this flag */
+               data.ioc_obdo1.o_flags = OBD_FL_OBDMDEXISTS;
        rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
        if (rc) {
                llapi_error(LLAPI_MSG_ERROR, rc,
@@ -1653,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)
@@ -1660,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;
@@ -1712,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);
@@ -1728,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)
@@ -1825,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)
@@ -1867,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;
@@ -1903,6 +2000,7 @@ again:
                }
                goto again;
        }
+
        return ret;
 }
 
@@ -2873,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;
@@ -2881,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);
@@ -3211,10 +3331,56 @@ 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);
 
-               separator = "\n";
+               if (verbose & VERBOSE_HASH_TYPE && !yaml)
+                       separator = " ";
+               else
+                       separator = "\n";
+       }
+
+       if ((verbose & VERBOSE_INHERIT) && lum->lum_magic == LMV_USER_MAGIC) {
+               llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
+               if (verbose & ~VERBOSE_INHERIT)
+                       llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit: ");
+               if (lum->lum_max_inherit == LMV_INHERIT_UNLIMITED)
+                       llapi_printf(LLAPI_MSG_NORMAL, "-1");
+               else if (lum->lum_max_inherit == LMV_INHERIT_NONE)
+                       llapi_printf(LLAPI_MSG_NORMAL, "0");
+               else
+                       llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
+                                    lum->lum_max_inherit);
+               if (verbose & VERBOSE_INHERIT && !yaml)
+                       separator = " ";
+               else
+                       separator = "\n";
+       }
+
+       if ((verbose & VERBOSE_INHERIT_RR) &&
+           lum->lum_magic == LMV_USER_MAGIC &&
+           lum->lum_stripe_offset == LMV_OFFSET_DEFAULT) {
+               llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
+               if (verbose & ~VERBOSE_INHERIT_RR)
+                       llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit_rr: ");
+               if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_UNLIMITED)
+                       llapi_printf(LLAPI_MSG_NORMAL, "-1");
+               else if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_NONE)
+                       llapi_printf(LLAPI_MSG_NORMAL, "0");
+               else
+                       llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
+                                    lum->lum_max_inherit_rr);
+               if (verbose & VERBOSE_INHERIT_RR && !yaml)
+                       separator = " ";
+               else
+                       separator = "\n";
        }
 
+       separator = "\n";
+
        if (verbose & VERBOSE_OBJID && lum->lum_magic != LMV_USER_MAGIC) {
                llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
                if (lum->lum_stripe_count > 0)
@@ -3504,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';
@@ -4005,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;
@@ -4047,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 };
@@ -4491,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;
@@ -4697,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)
 {
@@ -4726,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;
@@ -4751,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;
                        }
                }
 
@@ -4839,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;
@@ -4903,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))
@@ -5184,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;
@@ -5247,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,
@@ -5288,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
@@ -5821,39 +6056,6 @@ int llapi_get_connect_flags(const char *mnt, __u64 *flags)
 }
 
 /**
- * Get a 64-bit value representing the version of file data pointed by fd.
- *
- * Each write or truncate, flushed on OST, will change this value. You can use
- * this value to verify if file data was modified. This only checks the file
- * data, not metadata.
- *
- * \param  flags  0: no flush pages, usually used it the process has already
- *                 taken locks;
- *                LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
- *                  from clients;
- *                LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
- *                  pages from clients.
- *
- * \retval 0 on success.
- * \retval -errno on error.
- */
-int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
-{
-       int rc;
-       struct ioc_data_version idv;
-
-       idv.idv_flags = (__u32)flags;
-
-       rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
-       if (rc)
-               rc = -errno;
-       else
-               *data_version = idv.idv_version;
-
-       return rc;
-}
-
-/**
  * Flush cached pages from all clients.
  *
  * \param fd   File descriptor
@@ -5867,301 +6069,3 @@ int llapi_file_flush(int fd)
        return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
 }
 
-/*
- * Fetch layout version from OST objects. Layout version on OST objects are
- * only set when the file is a mirrored file AND after the file has been
- * written at least once.
- *
- * It actually fetches the least layout version from the objects.
- */
-int llapi_get_ost_layout_version(int fd, __u32 *layout_version)
-{
-       int rc;
-       struct ioc_data_version idv = { 0 };
-
-       rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
-       if (rc)
-               rc = -errno;
-       else
-               *layout_version = idv.idv_layout_version;
-
-       return rc;
-}
-
-/*
- * Create a file without any name and open it for read/write
- *
- * - file is created as if it were a standard file in the given \a directory
- * - file does not appear in \a directory and mtime does not change because
- *   the filename is handled specially by the Lustre MDS.
- * - file is destroyed at final close
- *
- * \param[in]  directory       directory from which to inherit layout/MDT idx
- * \param[in]  mdt_idx         MDT index on which the file is created,
- *                             \a idx == -1 means no specific MDT is requested
- * \param[in]  mode            standard open(2) mode
- * \param[in]  stripe_param    stripe parameters. May be NULL.
- *
- * \retval     a file descriptor on success.
- * \retval     -errno on error.
- */
-int llapi_create_volatile_param(const char *directory, int mdt_idx,
-                               int open_flags, mode_t mode,
-                               const struct llapi_stripe_param *stripe_param)
-{
-       char file_path[PATH_MAX];
-       int saved_errno = errno;
-       int fd;
-       unsigned int rnumber;
-       int rc;
-
-       do {
-               rnumber = random();
-               if (mdt_idx == -1)
-                       rc = snprintf(file_path, sizeof(file_path),
-                                     "%s/" LUSTRE_VOLATILE_HDR "::%.4X",
-                                     directory, rnumber);
-               else
-                       rc = snprintf(file_path, sizeof(file_path),
-                                     "%s/" LUSTRE_VOLATILE_HDR ":%.4X:%.4X",
-                                     directory, mdt_idx, rnumber);
-
-               if (rc < 0 || rc >= sizeof(file_path))
-                       return -ENAMETOOLONG;
-
-               /*
-                * Either open O_WRONLY or O_RDWR, creating RDONLY
-                * is non-sensical here
-                */
-               if ((open_flags & O_ACCMODE) == O_RDONLY)
-                       open_flags = O_RDWR | (open_flags & ~O_ACCMODE);
-
-               open_flags |= O_CREAT | O_EXCL | O_NOFOLLOW;
-
-               if (stripe_param != NULL) {
-                       fd = llapi_file_open_param(file_path, open_flags,
-                                                  mode, stripe_param);
-                       if (fd < 0)
-                               rc = fd;
-               } else {
-                       fd = open(file_path, open_flags, mode);
-                       if (fd < 0)
-                               rc = -errno;
-               }
-       } while (fd < 0 && rc == -EEXIST);
-
-       if (fd < 0) {
-               llapi_error(LLAPI_MSG_ERROR, rc,
-                           "Cannot create volatile file '%s' in '%s'",
-                           file_path + strlen(directory) + 1 +
-                           LUSTRE_VOLATILE_HDR_LEN,
-                           directory);
-               return rc;
-       }
-
-       /*
-        * Unlink file in case this wasn't a Lustre filesystem and the magic
-        * volatile filename wasn't handled as intended. The effect is the
-        * same. If volatile open was supported then we expect unlink() to
-        * return -ENOENT.
-        */
-       (void)unlink(file_path);
-
-       /*
-        * Since we are returning successfully we restore errno (and
-        * mask out possible EEXIST from open() and ENOENT from unlink().
-        */
-       errno = saved_errno;
-
-       return fd;
-}
-
-/*
- * Create a file without any name open it for read/write
- *
- * - file is created as if it were a standard file in the given \a directory
- * - file does not appear in \a directory and mtime does not change because
- *   the filename is handled specially by the Lustre MDS.
- * - file is removed at final close
- * - file modes are rw------- since it doesn't make sense to have a read-only
- *   or write-only file that cannot be opened again.
- * - if user wants another mode it must use fchmod() on the open file, no
- *   security problems arise because it cannot be opened by another process.
- *
- * \param[in]  directory       directory from which to inherit layout/MDT idx
- * \param[in]  idx             MDT index on which the file is created,
- *                             \a idx == -1 means no specific MDT is requested
- * \param[in]  open_flags      standard open(2) flags
- *
- * \retval     a file descriptor on success.
- * \retval     -errno on error.
- */
-int llapi_create_volatile_idx(const char *directory, int mdt_idx,
-                             int open_flags)
-{
-       return llapi_create_volatile_param(directory, mdt_idx, open_flags,
-                                          S_IRUSR | S_IWUSR, NULL);
-}
-
-/**
- * Swap the layouts between 2 file descriptors
- * the 2 files must be open for writing
- * first fd received the ioctl, second fd is passed as arg
- * this is assymetric but avoid use of root path for ioctl
- */
-int llapi_fswap_layouts_grouplock(int fd1, int fd2, __u64 dv1, __u64 dv2,
-                                 int gid, __u64 flags)
-{
-       struct lustre_swap_layouts      lsl;
-       struct stat                     st1;
-       struct stat                     st2;
-       int                             rc;
-
-       if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
-               rc = fstat(fd1, &st1);
-               if (rc < 0)
-                       return -errno;
-
-               rc = fstat(fd2, &st2);
-               if (rc < 0)
-                       return -errno;
-       }
-       lsl.sl_fd = fd2;
-       lsl.sl_flags = flags;
-       lsl.sl_gid = gid;
-       lsl.sl_dv1 = dv1;
-       lsl.sl_dv2 = dv2;
-       rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
-       if (rc < 0)
-               return -errno;
-
-       if (flags & (SWAP_LAYOUTS_KEEP_ATIME | SWAP_LAYOUTS_KEEP_MTIME)) {
-               struct timeval  tv1[2];
-               struct timeval  tv2[2];
-
-               memset(tv1, 0, sizeof(tv1));
-               memset(tv2, 0, sizeof(tv2));
-
-               if (flags & SWAP_LAYOUTS_KEEP_ATIME) {
-                       tv1[0].tv_sec = st1.st_atime;
-                       tv2[0].tv_sec = st2.st_atime;
-               } else {
-                       tv1[0].tv_sec = st2.st_atime;
-                       tv2[0].tv_sec = st1.st_atime;
-               }
-
-               if (flags & SWAP_LAYOUTS_KEEP_MTIME) {
-                       tv1[1].tv_sec = st1.st_mtime;
-                       tv2[1].tv_sec = st2.st_mtime;
-               } else {
-                       tv1[1].tv_sec = st2.st_mtime;
-                       tv2[1].tv_sec = st1.st_mtime;
-               }
-
-               rc = futimes(fd1, tv1);
-               if (rc < 0)
-                       return -errno;
-
-               rc = futimes(fd2, tv2);
-               if (rc < 0)
-                       return -errno;
-       }
-
-       return 0;
-}
-
-int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
-{
-       int     rc;
-       int     grp_id;
-
-       do
-               grp_id = random();
-       while (grp_id == 0);
-
-       rc = llapi_fswap_layouts_grouplock(fd1, fd2, dv1, dv2, grp_id, flags);
-       if (rc < 0)
-               return rc;
-
-       return 0;
-}
-
-/**
- * Swap the layouts between 2 files
- * the 2 files are open in write
- */
-int llapi_swap_layouts(const char *path1, const char *path2,
-                      __u64 dv1, __u64 dv2, __u64 flags)
-{
-       int     fd1, fd2, rc;
-
-       fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
-       if (fd1 < 0) {
-               rc = -errno;
-               llapi_error(LLAPI_MSG_ERROR, rc,
-                           "error: cannot open '%s' for write", path1);
-               goto out;
-       }
-
-       fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
-       if (fd2 < 0) {
-               rc = -errno;
-               llapi_error(LLAPI_MSG_ERROR, rc,
-                           "error: cannot open '%s' for write", path2);
-               goto out_close;
-       }
-
-       rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
-       if (rc < 0)
-               llapi_error(LLAPI_MSG_ERROR, rc,
-                           "error: cannot swap layout between '%s' and '%s'",
-                           path1, path2);
-
-       close(fd2);
-out_close:
-       close(fd1);
-out:
-       return rc;
-}
-
-/**
- * Take group lock.
- *
- * \param fd   File to lock.
- * \param gid  Group Identifier.
- *
- * \retval 0 on success.
- * \retval -errno on failure.
- */
-int llapi_group_lock(int fd, int gid)
-{
-       int rc;
-
-       rc = ioctl(fd, LL_IOC_GROUP_LOCK, gid);
-       if (rc < 0) {
-               rc = -errno;
-               llapi_error(LLAPI_MSG_ERROR, rc, "cannot get group lock");
-       }
-       return rc;
-}
-
-/**
- * Put group lock.
- *
- * \param fd   File to unlock.
- * \param gid  Group Identifier.
- *
- * \retval 0 on success.
- * \retval -errno on failure.
- */
-int llapi_group_unlock(int fd, int gid)
-{
-       int rc;
-
-       rc = ioctl(fd, LL_IOC_GROUP_UNLOCK, gid);
-       if (rc < 0) {
-               rc = -errno;
-               llapi_error(LLAPI_MSG_ERROR, rc, "cannot put group lock");
-       }
-       return rc;
-}