Whamcloud - gitweb
LU-14521 flr: delete mirror without volatile file
[fs/lustre-release.git] / lustre / utils / lfs.c
index 82fa2c5..2ad1dc0 100644 (file)
@@ -27,7 +27,6 @@
  */
 /*
  * This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
  *
  * lustre/utils/lfs.c
  *
@@ -85,6 +84,7 @@ static int lfs_getstripe(int argc, char **argv);
 static int lfs_getdirstripe(int argc, char **argv);
 static int lfs_setdirstripe(int argc, char **argv);
 static int lfs_rmentry(int argc, char **argv);
+static int lfs_unlink_foreign(int argc, char **argv);
 static int lfs_osts(int argc, char **argv);
 static int lfs_mdts(int argc, char **argv);
 static int lfs_df(int argc, char **argv);
@@ -138,6 +138,13 @@ static int lfs_migrate_to_dom(int fd, int fdv, char *name,
                              struct llapi_stripe_param *param,
                              struct llapi_layout *layout);
 
+struct pool_to_id_cbdata {
+       const char *pool;
+       __u32 id;
+};
+static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata);
+static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata);
+
 enum setstripe_origin {
        SO_SETSTRIPE,
        SO_MIGRATE,
@@ -190,43 +197,43 @@ static inline int lfs_mirror_delete(int argc, char **argv)
        "                 [--stripe-size|-S <stripe_size>]\n"           \
        "                 [--extension-size|--ext-size|-z]\n"           \
        "                 [--layout|-L <pattern>]\n"                    \
-       "                 [--mirror_count|-N[mirror_count]]\n"          \
+       "                 [--mirror-count|-N[mirror_count]]\n"          \
        "                 [--ost|-o <ost_indices>]\n"                   \
        "                 [--pool|-p <pool_name>]\n"                    \
        "                 [--yaml|-y <yaml_template_file>]\n"           \
        "                 [--copy=<lustre_src>]\n"
 
 #define SSM_HELP_COMMON \
-       "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
-       "\t              Using -C instead of -c allows overstriping, which\n" \
-       "\t              will place more than one stripe per OST if\n" \
-       "\t              stripe_count is greater than the number of OSTs\n" \
+       "\tstripe_count: Number of OSTs to stripe on (0=fs default, -1 all)\n" \
+       "\t              Using -C instead of -c allows overstriping, which\n"  \
+       "\t              will place more than one stripe per OST if\n"         \
+       "\t              stripe_count is greater than the number of OSTs.\n"   \
        "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
-       "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
-       "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
-       "\t              respectively)\n"                               \
-       "\textension_size:\n"                                           \
+       "\tstripe_size:  Number of bytes on each OST (0=fs default)\n"         \
+       "\t              Optional K, M, or G suffix (for KB, MB, GB\n"         \
+       "\t              respectively).  Must be a multiple of 64KiB.\n"       \
+       "\textension_size:\n"                                                  \
        "\t              Number of bytes the previous component is extended\n" \
-       "\t              each time. Can be specified with K, M, G (for KB,\n" \
-       "\t              MB, GB respectively)\n"                        \
-       "\tpool_name:    Name of OST pool to use (default none)\n"      \
-       "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"\
+       "\t              each time. Optional K, M, or G suffix (for KB,\n"     \
+       "\t              MB, GB respectively)\n"                               \
+       "\tpool_name:    Name of OST pool to use (default none)\n"             \
+       "\tlayout:       stripe pattern type: raid0, mdt (default raid0)\n"    \
        "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
-       "\t              Indices be specified in a format of:\n"        \
-       "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
-       "\t              Or:\n"                                         \
-       "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
-       "\t              If --pool is set with --ost then the OSTs\n"   \
-       "\t              must be the members of the pool.\n"            \
-       "\tcomp_end:     Extent end of component, start after previous end.\n"\
-       "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
-       "\t              respectively, -1 for EOF). Must be a multiple of\n"\
-       "\t              stripe_size.\n"                                      \
-       "\tyaml_template_file:\n"                                             \
-       "\t              YAML layout template file, can't be used with -c,\n" \
-       "\t              -i, -S, -p, -o, or -E arguments.\n"                  \
-       "\tlustre_src:   Lustre file/dir whose layout info is used to set\n"  \
-       "\t              another lustre file or directory, can't used with\n" \
+       "\t              Indices be specified in a format of:\n"               \
+       "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"               \
+       "\t              Or:\n"                                                \
+       "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"         \
+       "\t              If --pool is set with --ost then the OSTs\n"          \
+       "\t              must be the members of the pool.\n"                   \
+       "\tcomp_end:     Extent end of component, start after previous end.\n" \
+       "\t              Optional K, M, or G suffix (for KiB, MiB, GiB), or\n" \
+       "\t              -1 or 'eof' for max file size). Must be a multiple\n" \
+       "\t              of stripe_size and a multiple of 64KiB.\n"            \
+       "\tyaml_template_file:\n"                                              \
+       "\t              YAML layout template file, can't be used with -c,\n"  \
+       "\t              -i, -S, -p, -o, or -E arguments.\n"                   \
+       "\tlustre_src:   Lustre file/dir whose layout info is used to set\n"   \
+       "\t              another lustre file or directory, can't used with\n"  \
        "\t              -c, -i, -S, -p, -o, or -E arguments.\n"
 
 #define MIRROR_CREATE_HELP                                                    \
@@ -293,7 +300,7 @@ static inline int lfs_mirror_delete(int argc, char **argv)
        "setdirstripe|mkdir --foreign[=<foreign_type>] -x|-xattr <string> " \
                "[--mode|-o mode] [--flags <hex>] <dir>\n" \
        "\tmode: the mode of the directory\n" \
-       "\tforeign_type: none or daos\n"
+       "\tforeign_type: none or symlink\n"
 
 /**
  * command_t mirror_cmdlist - lfs mirror commands.
@@ -417,6 +424,12 @@ command_t cmdlist[] = {
         "\tcomp_flags:  'init' indicating all instantiated components\n"
         "\t             '^init' indicating all uninstantiated components\n"
         "\t-I and -F cannot be specified at the same time\n"
+        " or\n"
+        "To set or clear flags on a specific component\n"
+        "(note that this command can only be applied to mirrored files:\n"
+        "usage: setstripe --comp-set {-I comp_id|--comp-flags=comp_flags}\n"
+        "                            <filename>\n"
+        " or\n"
         "To create a file with a foreign (free format) layout:\n"
         "usage: setstripe --foreign[=<foreign_type>]\n"
         "                 --xattr|-x <layout_string> [--flags <hex>]\n"
@@ -436,7 +449,7 @@ command_t cmdlist[] = {
         "                 [--component-start[=[+-]comp_start]]\n"
         "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
         "                 [[!] --mirror-index=[+-]<index> |\n"
-        "                  [!] --mirror-id=[+-]<id>]\n"
+        "                  [!] --mirror-id=[+-]<id>] [--mirror-count|-N]\n"
         "                 <directory|filename> ..."},
        {"setdirstripe", lfs_setdirstripe, 0,
         "Create striped directory on specified MDT, same as mkdir.\n"
@@ -460,6 +473,11 @@ command_t cmdlist[] = {
         "will become inaccessable after this command. This can only be done\n"
         "by the administrator\n"
         "usage: rm_entry <dir>\n"},
+       {"unlink_foreign", lfs_unlink_foreign, 0,
+        "To remove the foreign file/dir.\n"
+        "Note: This is for files/dirs prevented to be removed using\n"
+        "unlink/rmdir, but works also for regular ones\n"
+        "usage: unlink_foreign <foreign_dir/file> [<foreign_dir/file> ...]\n"},
        {"pool_list", lfs_poollist, 0,
         "List pools or pool OSTs\n"
         "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
@@ -480,7 +498,6 @@ command_t cmdlist[] = {
         "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
         "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
         "     [[!] --projid <projid>]\n"
-        "     [[!] --foreign[=<foreign_type>]]\n"
         "     [[!] --layout|-L released,raid0,mdt]\n"
         "     [[!] --foreign[=<foreign_type>]]\n"
         "     [[!] --component-count [+-]<comp_cnt>]\n"
@@ -490,14 +507,12 @@ command_t cmdlist[] = {
         "     [[!] --mirror-count|-N [+-]<n>]\n"
         "     [[!] --mirror-state <[^]state>]\n"
         "     [[!] --mdt-count|-T [+-]<stripes>]\n"
-        "     [[!] --mdt-hash|-H <hashtype>\n"
+        "     [[!] --mdt-hash|-H <[^][blm],[^]fnv_1a_64,all_char,crush,...>\n"
         "     [[!] --mdt-index|-m <uuid|index,...>]\n"
         "\t !: used before an option indicates 'NOT' requested attribute\n"
         "\t -: used before a value indicates less than requested value\n"
         "\t +: used before a value indicates more than requested value\n"
-        "\thashtype:   hash type of the striped directory.\n"
-        "\t            fnv_1a_64 FNV-1a hash algorithm\n"
-        "\t            all_char  sum of characters % MDT_COUNT\n"},
+        "\t ^: used before a flag indicates to exclude it\n"},
        {"check", lfs_check, 0,
         "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
         "or all the servers (MGTs, MDTs and OSTs).\n"
@@ -571,8 +586,9 @@ command_t cmdlist[] = {
         "         clear the project inherit flag and ID on the file or directory\n"
        },
 #endif
-       {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
-        "usage: flushctx [-k] [mountpoint...]"},
+       {"flushctx", lfs_flushctx, 0,
+        "Flush security context for current user.\n"
+        "usage: flushctx [-k] [-r] [mountpoint...]"},
        {"changelog", lfs_changelog, 0,
         "Show the metadata changes on an MDT."
         "\nusage: changelog <mdtname> [startrec [endrec]]"},
@@ -584,7 +600,8 @@ command_t cmdlist[] = {
        {"fid2path", lfs_fid2path, 0,
         "Resolve the full path(s) for given FID(s). For a specific hardlink "
         "specify link number <linkno>.\n"
-        "usage: fid2path [-c] [--link|-l <linkno>] <fsname|root> <fid> ..."},
+        "usage: fid2path [--print-fid|-f] [--print-link|-c] [--link|-l <linkno>] "
+        "<fsname|root> <fid>..."},
        {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
         "usage: path2fid [--parents] <path> ..."},
        {"rmfid", lfs_rmfid, 0, "Remove file(s) by FID(s)\n"
@@ -761,9 +778,6 @@ enum {
        MIGRATION_VERBOSE       = 0x0008,
 };
 
-static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
-                               struct llapi_layout *layout);
-
 static int
 migrate_open_files(const char *name, __u64 migration_flags,
                   const struct llapi_stripe_param *param,
@@ -839,12 +853,17 @@ migrate_open_files(const char *name, __u64 migration_flags,
                }
 
                /* create, open a volatile file, use caching (ie no directio) */
-               if (layout)
-                       fdv = lfs_component_create(volatile_file, open_flags,
-                                                  open_mode, layout);
-               else
+               if (layout) {
+                       /* Returns -1 and sets errno on error: */
+                       fdv = llapi_layout_file_open(volatile_file, open_flags,
+                                                    open_mode, layout);
+                       if (fdv < 0)
+                               fdv = -errno;
+               } else {
+                       /* Does the right thing on error: */
                        fdv = llapi_file_open_param(volatile_file, open_flags,
                                                    open_mode, param);
+               }
        } while (fdv < 0 && (rc = fdv) == -EEXIST);
 
        if (rc < 0) {
@@ -903,14 +922,13 @@ out:
 static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
 {
        struct llapi_layout *layout;
-       size_t   buf_size = 4 * 1024 * 1024;
-       void    *buf = NULL;
-       ssize_t  rsize = -1;
-       ssize_t  wsize = 0;
-       size_t   rpos = 0;
-       size_t   wpos = 0;
-       off_t    bufoff = 0;
-       int      rc;
+       size_t buf_size = 4 * 1024 * 1024;
+       void *buf = NULL;
+       off_t pos = 0;
+       off_t data_end = 0;
+       size_t page_size = sysconf(_SC_PAGESIZE);
+       bool sparse;
+       int rc;
 
        layout = llapi_layout_get_by_fd(fd_src, 0);
        if (layout) {
@@ -924,48 +942,85 @@ static int migrate_copy_data(int fd_src, int fd_dst, int (*check_file)(int))
        }
 
        /* Use a page-aligned buffer for direct I/O */
-       rc = posix_memalign(&buf, getpagesize(), buf_size);
+       rc = posix_memalign(&buf, page_size, buf_size);
        if (rc != 0)
                return -rc;
 
+       sparse = llapi_file_is_sparse(fd_src);
+       if (sparse) {
+               rc = ftruncate(fd_dst, pos);
+               if (rc < 0) {
+                       rc = -errno;
+                       return rc;
+               }
+       }
+
        while (1) {
-               /*
-                * read new data only if we have written all
-                * previously read data
-                */
-               if (wpos == rpos) {
-                       if (check_file) {
-                               rc = check_file(fd_src);
+               off_t data_off;
+               size_t to_read, to_write;
+               ssize_t rsize;
+
+               if (sparse && pos >= data_end) {
+                       size_t data_size;
+
+                       data_off = llapi_data_seek(fd_src, pos, &data_size);
+                       if (data_off < 0) {
+                               /* Non-fatal, switch to full copy */
+                               sparse = false;
+                               continue;
+                       }
+                       /* hole at the end of file, truncate up to it */
+                       if (!data_size) {
+                               rc = ftruncate(fd_dst, data_off);
                                if (rc < 0)
-                                       break;
+                                       goto out;
                        }
+                       pos = data_off & ~(page_size - 1);
+                       data_end = data_off + data_size;
+                       to_read = ((data_end - pos - 1) | (page_size - 1)) + 1;
+                       to_read = MIN(to_read, buf_size);
+               } else {
+                       to_read = buf_size;
+               }
 
-                       rsize = read(fd_src, buf, buf_size);
-                       if (rsize < 0) {
-                               rc = -errno;
-                               break;
-                       }
-                       rpos += rsize;
-                       bufoff = 0;
+               if (check_file) {
+                       rc = check_file(fd_src);
+                       if (rc < 0)
+                               goto out;
                }
-               /* eof ? */
-               if (rsize == 0)
-                       break;
 
-               wsize = write(fd_dst, buf + bufoff, rpos - wpos);
-               if (wsize < 0) {
+               rsize = pread(fd_src, buf, to_read, pos);
+               if (rsize < 0) {
                        rc = -errno;
+                       goto out;
+               }
+               /* EOF */
+               if (rsize == 0)
                        break;
+
+               to_write = rsize;
+               while (to_write > 0) {
+                       ssize_t written;
+
+                       written = pwrite(fd_dst, buf, to_write, pos);
+                       if (written < 0) {
+                               rc = -errno;
+                               goto out;
+                       }
+                       pos += written;
+                       to_write -= written;
                }
-               wpos += wsize;
-               bufoff += wsize;
+               if (rc || rsize < to_read)
+                       break;
        }
 
-       if (rc == 0) {
-               rc = fsync(fd_dst);
-               if (rc < 0)
-                       rc = -errno;
-       }
+       rc = fsync(fd_dst);
+       if (rc < 0)
+               rc = -errno;
+out:
+       /* Try to avoid page cache pollution after migration. */
+       (void)posix_fadvise(fd_src, 0, 0, POSIX_FADV_DONTNEED);
+       (void)posix_fadvise(fd_dst, 0, 0, POSIX_FADV_DONTNEED);
 
        free(buf);
        return rc;
@@ -1115,7 +1170,40 @@ static int migrate_nonblock(int fd, int fdv)
        return 0;
 }
 
-static int lfs_component_set(char *fname, int comp_id,
+static
+int lfs_layout_compid_by_pool(char *fname, const char *pool, int *comp_id)
+{
+       struct pool_to_id_cbdata data = { .pool = pool };
+       struct llapi_layout *layout = NULL;
+       int rc;
+
+       layout = llapi_layout_get_by_path(fname, 0);
+       if (!layout) {
+               fprintf(stderr,
+                       "error %s: file '%s' couldn't get layout: rc=%d\n",
+                       progname, fname, errno);
+               rc = -errno;
+               goto free_layout;
+       }
+       rc = llapi_layout_sanity(layout, false, true);
+       if (rc < 0) {
+               llapi_layout_sanity_perror(errno);
+               goto free_layout;
+       }
+       rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool, &data);
+       if (rc < 0)
+               goto free_layout;
+
+       *comp_id = data.id;
+       rc = 0;
+
+free_layout:
+       if (layout)
+               llapi_layout_free(layout);
+       return rc;
+}
+
+static int lfs_component_set(char *fname, int comp_id, const char *pool,
                             __u32 flags, __u32 neg_flags)
 {
        __u32 ids[2];
@@ -1123,6 +1211,18 @@ static int lfs_component_set(char *fname, int comp_id,
        size_t count = 0;
        int rc;
 
+       if (!comp_id) {
+               if (pool == NULL) {
+                       fprintf(stderr,
+                               "error %s: neither component id nor pool is specified\n",
+                               progname);
+                       return -EINVAL;
+               }
+               rc = lfs_layout_compid_by_pool(fname, pool, &comp_id);
+               if (rc)
+                       return rc;
+       }
+
        if (flags) {
                ids[count] = comp_id;
                flags_array[count] = flags;
@@ -1330,13 +1430,24 @@ out_closed:
 static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
 {
        char *name;
-
-       if (!string)
-               return -EINVAL;
+       char *dup_string = NULL;
+       int rc = 0;
 
        *flags = 0;
        *neg_flags = 0;
-       for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
+
+       if (!string || !string[0])
+               return -EINVAL;
+
+       dup_string = strdup(string);
+       if (!dup_string) {
+               llapi_printf(LLAPI_MSG_ERROR,
+                            "%s: insufficient memory\n",
+                            progname);
+               return -ENOMEM;
+       }
+
+       for (name = strtok(dup_string, ","); name; name = strtok(NULL, ",")) {
                bool found = false;
                int i;
 
@@ -1357,17 +1468,79 @@ static int comp_str2flags(char *string, __u32 *flags, __u32 *neg_flags)
                        llapi_printf(LLAPI_MSG_ERROR,
                                     "%s: component flag '%s' not supported\n",
                                     progname, name);
-                       return -EINVAL;
+                       rc = -EINVAL;
+                       goto out_free;
                }
        }
 
        if (!*flags && !*neg_flags)
-               return -EINVAL;
+               rc = -EINVAL;
 
        /* don't allow to set and exclude the same flag */
        if (*flags & *neg_flags)
+               rc = -EINVAL;
+
+out_free:
+       free(dup_string);
+       return rc;
+}
+
+static int mdthash_input(char *string, __u32 *inflags,
+                        __u32 *exflags, __u32 *type)
+{
+       char *name;
+       struct mhf_list {
+               char *name;
+               __u32 flag;
+       } mhflist[] = {
+               {"migrating", LMV_HASH_FLAG_MIGRATION},
+               {"badtype", LMV_HASH_FLAG_BAD_TYPE},
+               {"lostlmv", LMV_HASH_FLAG_LOST_LMV},
+       };
+
+       if (string == NULL)
                return -EINVAL;
 
+       *inflags = 0;
+       *exflags = 0;
+       *type = 0;
+       for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
+               bool found = false;
+               int i;
+
+               for (i = 0; i < ARRAY_SIZE(mhflist); i++) {
+                       if (strcmp(name, mhflist[i].name) == 0 ||
+                           name[0] == mhflist[i].name[0]) {
+                               *inflags |= mhflist[i].flag;
+                               found = true;
+                       } else if (name[0] == '^' &&
+                                  (strcmp(name + 1, mhflist[i].name) == 0 ||
+                                   name[1] == mhflist[i].name[0])) {
+                               *exflags |= mhflist[i].flag;
+                               found = true;
+                       }
+               }
+               if (!found) {
+                       i = check_hashtype(name);
+                       if (i > 0) {
+                               *type |= 1 << i;
+                               continue;
+                       }
+                       llapi_printf(LLAPI_MSG_ERROR,
+                                    "%s: invalid mdt_hash value '%s'\n",
+                                    progname, name);
+                       return -EINVAL;
+               }
+       }
+
+       /* don't allow to include and exclude the same flag */
+       if (*inflags & *exflags) {
+               llapi_printf(LLAPI_MSG_ERROR,
+                            "%s: include and exclude same flag '%s'\n",
+                            progname, string);
+               return -EINVAL;
+       }
+
        return 0;
 }
 
@@ -1766,7 +1939,7 @@ out:
 }
 
 static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
-                               bool inherit)
+                               bool inherit, uint32_t flags)
 {
        struct llapi_layout *f_layout = NULL;
        struct ll_ioc_lease *data = NULL;
@@ -1794,7 +1967,9 @@ static int mirror_extend_layout(char *name, struct llapi_layout *m_layout,
                        goto out;
                }
        }
-       rc = migrate_open_files(name, 0, NULL, m_layout, &fd, &fdv);
+       llapi_layout_comp_flags_set(m_layout, flags);
+       rc = migrate_open_files(name, MIGRATION_NONDIRECT, NULL, m_layout, &fd,
+                               &fdv);
        if (rc < 0)
                goto out;
 
@@ -1863,7 +2038,8 @@ static int mirror_extend(char *fname, struct mirror_args *mirror_list,
                        while (mirror_count > 0) {
                                rc = mirror_extend_layout(fname,
                                                        mirror_list->m_layout,
-                                                       mirror_list->m_inherit);
+                                                       mirror_list->m_inherit,
+                                                       mirror_list->m_flags);
                                if (rc)
                                        break;
 
@@ -1909,10 +2085,26 @@ static int find_comp_id(struct llapi_layout *layout, void *cbdata)
        return LLAPI_LAYOUT_ITER_CONT;
 }
 
-struct pool_to_id_cbdata {
-       const char *pool;
-       __u32 id;
-};
+static int find_mirror_id_by_pool(struct llapi_layout *layout, void *cbdata)
+{
+       char buf[LOV_MAXPOOLNAME + 1];
+       struct pool_to_id_cbdata *d = (void *)cbdata;
+       uint32_t id;
+       int rc;
+
+       rc = llapi_layout_pool_name_get(layout, buf, sizeof(buf));
+       if (rc < 0)
+               return rc;
+       if (strcmp(d->pool, buf))
+               return LLAPI_LAYOUT_ITER_CONT;
+
+       rc = llapi_layout_mirror_id_get(layout, &id);
+       if (rc < 0)
+               return rc;
+       d->id = id;
+
+       return LLAPI_LAYOUT_ITER_STOP;
+}
 
 static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
 {
@@ -1927,7 +2119,7 @@ static int find_comp_id_by_pool(struct llapi_layout *layout, void *cbdata)
        if (strcmp(d->pool, buf))
                return LLAPI_LAYOUT_ITER_CONT;
 
-       rc = llapi_layout_mirror_id_get(layout, &id);
+       rc = llapi_layout_comp_id_get(layout, &id);
        if (rc < 0)
                return rc;
        d->id = id;
@@ -2014,8 +2206,16 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
        __u32 mirror_id;
        int mdt_index;
        int fd, fdv;
+       bool purge = true; /* delete mirror by setting fdv=fd */
        int rc;
 
+       if (victim_file && (strcmp(fname, victim_file) == 0)) {
+               fprintf(stderr,
+                       "error %s: the source file '%s' and -f file are the same\n",
+                       progname, fname);
+               return -EINVAL;
+       }
+
        /* check fname contains mirror with mirror_id/comp_id */
        layout = llapi_layout_get_by_path(fname, 0);
        if (!layout) {
@@ -2048,7 +2248,7 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
        if (mflags & MF_COMP_POOL) {
                struct pool_to_id_cbdata data = { .pool = pool };
 
-               rc = llapi_layout_comp_iterate(layout, find_comp_id_by_pool,
+               rc = llapi_layout_comp_iterate(layout, find_mirror_id_by_pool,
                                               &data);
                mirror_id = data.id;
        } else if (mflags & MF_COMP_ID) {
@@ -2118,6 +2318,7 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
                goto close_fd;
        }
 
+again:
        if (!victim_file) {
                /* use a temp file to store the splitted layout */
                if (mflags & MF_DESTROY) {
@@ -2129,8 +2330,17 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
                                goto close_fd;
                        }
 
-                       fdv = llapi_create_volatile_idx(parent, mdt_index,
-                                                       O_LOV_DELAY_CREATE);
+                       if (purge) {
+                               /* don't use volatile file for mirror destroy */
+                               fdv = fd;
+                       } else {
+                               /**
+                                * try the old way to delete mirror using
+                                * volatile file.
+                                */
+                               fdv = llapi_create_volatile_idx(parent,
+                                               mdt_index, O_LOV_DELAY_CREATE);
+                       }
                } else {
                        snprintf(victim, sizeof(victim), "%s.mirror~%u",
                                 fname, mirror_id);
@@ -2171,6 +2381,12 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
        data->lil_ids[1] = mirror_id;
        rc = llapi_lease_set(fd, data);
        if (rc <= 0) {
+               if (rc == -EINVAL && purge) {
+                       /* could be old MDS which prohibit fd==fdv */
+                       purge = false;
+                       goto again;
+
+               }
                if (rc == 0) /* lost lease lock */
                        rc = -EBUSY;
                fprintf(stderr,
@@ -2182,7 +2398,8 @@ static int mirror_split(const char *fname, __u32 id, const char *pool,
        free(data);
 
 close_victim:
-       close(fdv);
+       if (!purge)
+               close(fdv);
 close_fd:
        close(fd);
 free_layout:
@@ -2299,16 +2516,19 @@ static int parse_targets(__u32 *tgts, int size, int offset, char *arg,
                end_of_loop = *ptr == '\0';
                *ptr = '\0';
 
+               errno = 0;
                start_index = strtol(arg, &endptr, 0);
                if (endptr == arg) /* no data at all */
                        break;
-               if (*endptr != '-' && *endptr != '\0') /* has invalid data */
+               if (errno != 0 || start_index < -1 ||
+                   (*endptr != '-' && *endptr != '\0'))
                        break;
 
                end_index = start_index;
                if (*endptr == '-') {
+                       errno = 0;
                        end_index = strtol(endptr + 1, &endptr, 0);
-                       if (*endptr != '\0')
+                       if (errno != 0 || *endptr != '\0' || end_index < -1)
                                break;
                        if (end_index < start_index)
                                break;
@@ -3310,27 +3530,42 @@ static int lfs_setstripe_internal(int argc, char **argv,
                case LFS_COMP_NO_VERIFY_OPT:
                        mirror_flags |= MF_NO_VERIFY;
                        break;
-               case LFS_MIRROR_ID_OPT:
-                       mirror_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || mirror_id == 0) {
+               case LFS_MIRROR_ID_OPT: {
+                       unsigned long int id;
+
+                       errno = 0;
+                       id = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' || id == 0 ||
+                           id > UINT16_MAX) {
                                fprintf(stderr,
                                        "%s %s: invalid mirror ID '%s'\n",
                                        progname, argv[0], optarg);
                                goto usage_error;
                        }
+
+                       mirror_id = (__u16)id;
                        break;
+               }
                case LFS_LAYOUT_FLAGS_OPT: {
                        uint32_t neg_flags;
 
                        /* check for numeric flags (foreign and mirror cases) */
                        if (setstripe_mode && !mirror_mode && !last_mirror) {
+                               errno = 0;
                                flags = strtoul(optarg, &end, 16);
-                               if (*end != '\0') {
+                               if (errno != 0 || *end != '\0' ||
+                                   flags >= UINT32_MAX) {
                                        fprintf(stderr,
-                                               "%s %s: bad flags '%s'\n",
+                                               "%s %s: invalid hex flags '%s'\n",
                                                progname, argv[0], optarg);
                                        return CMD_HELP;
                                }
+                               if (!foreign_mode) {
+                                       fprintf(stderr,
+                                               "%s %s: hex flags must be specified with --foreign option\n",
+                                               progname, argv[0]);
+                                       return CMD_HELP;
+                               }
                                break;
                        }
 
@@ -3376,6 +3611,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                                        optarg);
                                                return CMD_HELP;
                                        }
+                               } else if (type >= UINT32_MAX) {
+                                       fprintf(stderr,
+                                               "%s %s: invalid foreign type '%s'\n",
+                                               progname, argv[0], optarg);
+                                       return CMD_HELP;
                                }
                        }
                        foreign_mode = true;
@@ -3416,8 +3656,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        lsa.lsa_pattern = LLAPI_LAYOUT_OVERSTRIPING;
                        /* fall through */
                case 'c':
+                       errno = 0;
                        lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0'||
+                           lsa.lsa_stripe_count < -1 ||
+                           lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
                                fprintf(stderr,
                                        "%s %s: invalid stripe count '%s'\n",
                                        progname, argv[0], optarg);
@@ -3465,9 +3708,13 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                lsa.lsa_comp_end = LUSTRE_EOF;
                        } else {
                                result = llapi_parse_size(optarg,
-                                                       &lsa.lsa_comp_end,
-                                                       &size_units, 0);
-                               if (result) {
+                                                         &lsa.lsa_comp_end,
+                                                         &size_units, 0);
+                               /* assume units of KB if too small */
+                               if (lsa.lsa_comp_end < 4096)
+                                       lsa.lsa_comp_end *= 1024;
+                               if (result ||
+                                   lsa.lsa_comp_end & (LOV_MIN_STRIPE_SIZE - 1)) {
                                        fprintf(stderr,
                                                "%s %s: invalid component end '%s'\n",
                                                progname, argv[0], optarg);
@@ -3491,8 +3738,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        }
                        break;
                case 'i':
+                       errno = 0;
                        lsa.lsa_stripe_off = strtol(optarg, &end, 0);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' ||
+                           lsa.lsa_stripe_off < -1 ||
+                           lsa.lsa_stripe_off > LOV_V1_INSANE_STRIPE_COUNT) {
                                fprintf(stderr,
                                        "%s %s: invalid stripe offset '%s'\n",
                                        progname, argv[0], optarg);
@@ -3597,8 +3847,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        }
                        mirror_count = 1;
                        if (optarg) {
+                               errno = 0;
                                mirror_count = strtoul(optarg, &end, 0);
-                               if (*end != '\0' || mirror_count == 0) {
+                               if (errno != 0 || *end != '\0' ||
+                                   mirror_count == 0 ||
+                                   mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
                                        fprintf(stderr,
                                                "error: %s: bad mirror count: %s\n",
                                                progname, optarg);
@@ -3680,7 +3933,11 @@ static int lfs_setstripe_internal(int argc, char **argv,
                case 'S':
                        result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
                                                  &size_units, 0);
-                       if (result) {
+                       /* assume units of KB if too small to be valid */
+                       if (lsa.lsa_stripe_size < 4096)
+                               lsa.lsa_stripe_size *= 1024;
+                       if (result ||
+                           lsa.lsa_stripe_size & (LOV_MIN_STRIPE_SIZE - 1)) {
                                fprintf(stderr,
                                        "%s %s: invalid stripe size '%s'\n",
                                        progname, argv[0], optarg);
@@ -3802,7 +4059,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
                }
        }
 
-       if (comp_set && !comp_id) {
+       if (comp_set && !comp_id && !lsa.lsa_pool_name) {
                fprintf(stderr,
                        "%s %s: --component-set doesn't have component-id set\n",
                        progname, argv[0]);
@@ -4039,8 +4296,10 @@ static int lfs_setstripe_internal(int argc, char **argv,
                        layout = llapi_layout_get_by_path(template ?: fname, 0);
                        if (!layout) {
                                fprintf(stderr,
-                                       "%s: can't create composite layout from file %s.\n",
-                                       progname, template ?: fname);
+                                       "%s: can't create composite layout from file %s: %s\n",
+                                       progname, template ?: fname,
+                                       strerror(errno));
+                               result = -errno;
                                goto error;
                        }
                }
@@ -4052,6 +4311,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                             layout);
                } else if (comp_set != 0) {
                        result = lfs_component_set(fname, comp_id,
+                                                  lsa.lsa_pool_name,
                                                   lsa.lsa_comp_flags,
                                                   lsa.lsa_comp_neg_flags);
                } else if (comp_del != 0) {
@@ -4078,6 +4338,12 @@ static int lfs_setstripe_internal(int argc, char **argv,
                                comp_id = mirror_id;
                        else
                                mirror_flags |= MF_COMP_ID;
+                       if (has_m_file && !strcmp(fname, mirror_list->m_file)) {
+                               fprintf(stderr,
+                                       "%s: the file specified by -f cannot be same as the source file '%s'\n",
+                                       progname, fname);
+                               goto usage_error;
+                       }
                        result = mirror_split(fname, comp_id, lsa.lsa_pool_name,
                                              mirror_flags,
                                              has_m_file ? mirror_list->m_file :
@@ -4137,20 +4403,21 @@ static int lfs_poollist(int argc, char **argv)
        return llapi_poollist(argv[1]);
 }
 
+#define FP_DEFAULT_TIME_MARGIN (24 * 60 * 60)
 static time_t set_time(struct find_param *param, time_t *time, time_t *set,
                       char *str)
 {
        long long t = 0;
-       int res = 0;
+       int sign = 0;
        char *endptr = "AD";
        char *timebuf;
 
        if (str[0] == '+')
-               res = 1;
+               sign = 1;
        else if (str[0] == '-')
-               res = -1;
+               sign = -1;
 
-       if (res)
+       if (sign)
                str++;
 
        for (timebuf = str; *endptr && *(endptr + 1); timebuf = endptr + 1) {
@@ -4162,9 +4429,12 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set,
                        unit *= 52; /* 52 weeks + 1 day below */
                case  'w':      /* fallthrough */
                        unit *= 7;
+                       if (param->fp_time_margin == FP_DEFAULT_TIME_MARGIN)
+                               param->fp_time_margin *= (1 + unit / 52);
+                       unit += (*endptr == 'y'); /* +1 day for 365 days/year */
                case '\0': /* days are default unit if none used */
                case  'd':      /* fallthrough */
-                       unit = (unit + (*endptr == 'y')) * 24;
+                       unit *= 24;
                case  'h':      /* fallthrough */
                        unit *= 60;
                case  'm':      /* fallthrough */
@@ -4186,7 +4456,7 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set,
                t += val * unit;
        }
        if (*time < t) {
-               if (res != 0)
+               if (sign != 0)
                        str--;
                fprintf(stderr, "%s find: bad time '%s': too large\n",
                        progname, str);
@@ -4195,7 +4465,7 @@ static time_t set_time(struct find_param *param, time_t *time, time_t *set,
 
        *set = *time - t;
 
-       return res;
+       return sign;
 }
 
 static int str2quotaid(__u32 *id, const char *arg)
@@ -4206,8 +4476,7 @@ static int str2quotaid(__u32 *id, const char *arg)
        projid_tmp = strtoul(arg, &endptr, 10);
        if (*endptr != '\0')
                return -EINVAL;
-       if (projid_tmp > UINT32_MAX ||
-           (projid_tmp == ULONG_MAX && (errno == ERANGE)))
+       if (projid_tmp >= UINT32_MAX)
                return -ERANGE;
 
        *id = projid_tmp;
@@ -4298,7 +4567,7 @@ static int lfs_find(int argc, char **argv)
        struct find_param param = {
                .fp_max_depth = -1,
                .fp_quiet = 1,
-               .fp_time_margin = 24 * 60 * 60,
+               .fp_time_margin = FP_DEFAULT_TIME_MARGIN,
        };
        struct option long_opts[] = {
        { .val = 'A',   .name = "atime",        .has_arg = required_argument },
@@ -4322,8 +4591,6 @@ static int lfs_find(int argc, char **argv)
                                                .has_arg = required_argument },
        { .val = LFS_MIRROR_STATE_OPT,
                        .name = "mirror-state", .has_arg = required_argument },
-       { .val = LFS_LAYOUT_FOREIGN_OPT,
-                       .name = "foreign",      .has_arg = optional_argument},
        { .val = LFS_NEWERXY_OPT,
                        .name = "newer",        .has_arg = required_argument},
        { .val = LFS_NEWERXY_OPT,
@@ -4541,8 +4808,10 @@ static int lfs_find(int argc, char **argv)
                                optarg++;
                        }
 
+                       errno = 0;
                        param.fp_comp_count = strtoul(optarg, &endptr, 0);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' ||
+                           param.fp_comp_count > UINT32_MAX) {
                                fprintf(stderr,
                                        "error: bad component count '%s'\n",
                                        optarg);
@@ -4615,8 +4884,10 @@ static int lfs_find(int argc, char **argv)
                                optarg++;
                        }
 
+                       errno = 0;
                        param.fp_stripe_count = strtoul(optarg, &endptr, 0);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' ||
+                           param.fp_stripe_count > LOV_MAX_STRIPE_COUNT) {
                                fprintf(stderr,
                                        "error: bad stripe_count '%s'\n",
                                        optarg);
@@ -4627,7 +4898,15 @@ static int lfs_find(int argc, char **argv)
                        param.fp_exclude_stripe_count = !!neg_opt;
                        break;
                case 'D':
+                       errno = 0;
                        param.fp_max_depth = strtol(optarg, 0, 0);
+                       if (errno != 0 || param.fp_max_depth < 0) {
+                               fprintf(stderr,
+                                       "error: bad maxdepth '%s'\n",
+                                       optarg);
+                               ret = -1;
+                               goto err;
+                       }
                        break;
                case 'E':
                        if (optarg[0] == '+') {
@@ -4646,6 +4925,9 @@ static int lfs_find(int argc, char **argv)
                                rc = llapi_parse_size(optarg,
                                                &param.fp_comp_end,
                                                &param.fp_comp_end_units, 0);
+                               /* assume units of KB if too small */
+                               if (param.fp_comp_end < 4096)
+                                       param.fp_comp_end *= 1024;
                        }
                        if (rc) {
                                fprintf(stderr,
@@ -4673,6 +4955,11 @@ static int lfs_find(int argc, char **argv)
                                                        optarg);
                                                return CMD_HELP;
                                        }
+                               } else if (type >= UINT32_MAX) {
+                                       fprintf(stderr,
+                                               "%s %s: invalid foreign type '%s'\n",
+                                               progname, argv[0], optarg);
+                                       return CMD_HELP;
                                }
                        }
                        param.fp_foreign_type = type;
@@ -4842,14 +5129,15 @@ static int lfs_find(int argc, char **argv)
                        param.fp_check_gid = 1;
                        break;
                case 'H':
-                       param.fp_hash_type = check_hashtype(optarg);
-                       if (param.fp_hash_type == 0) {
-                               fprintf(stderr, "error: bad hash_type '%s'\n",
-                                       optarg);
+                       rc = mdthash_input(optarg, &param.fp_hash_inflags,
+                                          &param.fp_hash_exflags,
+                                          &param.fp_hash_type);
+                       if (rc) {
                                ret = -1;
                                goto err;
                        }
-                       param.fp_check_hash_type = 1;
+                       if (param.fp_hash_inflags || param.fp_hash_exflags)
+                               param.fp_check_hash_flag = 1;
                        param.fp_exclude_hash_type = !!neg_opt;
                        break;
                case 'l':
@@ -4890,8 +5178,10 @@ static int lfs_find(int argc, char **argv)
                                optarg++;
                        }
 
+                       errno = 0;
                        param.fp_mirror_count = strtoul(optarg, &endptr, 0);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' ||
+                           param.fp_mirror_count > LUSTRE_MIRROR_COUNT_MAX) {
                                fprintf(stderr,
                                        "error: bad mirror count '%s'\n",
                                        optarg);
@@ -5052,6 +5342,9 @@ err_free:
 
                        ret = llapi_parse_size(optarg, &param.fp_stripe_size,
                                               &param.fp_stripe_size_units, 0);
+                       /* assume units of KB if too small to be valid */
+                       if (param.fp_stripe_size < 4096)
+                               param.fp_stripe_size *= 1024;
                        if (ret) {
                                fprintf(stderr, "error: bad stripe_size '%s'\n",
                                        optarg);
@@ -5100,8 +5393,10 @@ err_free:
                                optarg++;
                        }
 
+                       errno = 0;
                        param.fp_mdt_count = strtoul(optarg, &endptr, 0);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' ||
+                           param.fp_mdt_count >= UINT32_MAX) {
                                fprintf(stderr, "error: bad mdt_count '%s'\n",
                                        optarg);
                                ret = -1;
@@ -5317,7 +5612,9 @@ static int lfs_getstripe_internal(int argc, char **argv,
                                param->fp_max_depth = 0;
                        }
                        break;
-               case LFS_MIRROR_INDEX_OPT:
+               case LFS_MIRROR_INDEX_OPT: {
+                       unsigned long int mirror_index;
+
                        if (optarg[0] == '+') {
                                param->fp_mirror_index_sign = -1;
                                optarg++;
@@ -5326,14 +5623,19 @@ static int lfs_getstripe_internal(int argc, char **argv,
                                optarg++;
                        }
 
-                       param->fp_mirror_index = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || (param->fp_mirror_index == 0 &&
+                       errno = 0;
+                       mirror_index = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' ||
+                           mirror_index > UINT16_MAX || (mirror_index == 0 &&
                            param->fp_mirror_index_sign == 0 && neg_opt == 0)) {
                                fprintf(stderr,
                                        "%s %s: invalid mirror index '%s'\n",
                                        progname, argv[0], optarg);
                                return CMD_HELP;
                        }
+
+                       param->fp_mirror_index = (__u16)mirror_index;
+
                        if (param->fp_mirror_id != 0) {
                                fprintf(stderr,
                                        "%s %s: can't specify both mirror index and mirror ID\n",
@@ -5343,7 +5645,10 @@ static int lfs_getstripe_internal(int argc, char **argv,
                        param->fp_check_mirror_index = 1;
                        param->fp_exclude_mirror_index = !!neg_opt;
                        break;
-               case LFS_MIRROR_ID_OPT:
+               }
+               case LFS_MIRROR_ID_OPT: {
+                       unsigned long int mirror_id;
+
                        if (optarg[0] == '+') {
                                param->fp_mirror_id_sign = -1;
                                optarg++;
@@ -5352,14 +5657,19 @@ static int lfs_getstripe_internal(int argc, char **argv,
                                optarg++;
                        }
 
-                       param->fp_mirror_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || (param->fp_mirror_id == 0 &&
+                       errno = 0;
+                       mirror_id = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' ||
+                           mirror_id > UINT16_MAX || (mirror_id == 0 &&
                            param->fp_mirror_id_sign == 0 && neg_opt == 0)) {
                                fprintf(stderr,
                                        "%s %s: invalid mirror ID '%s'\n",
                                        progname, argv[0], optarg);
                                return CMD_HELP;
                        }
+
+                       param->fp_mirror_id = (__u16)mirror_id;
+
                        if (param->fp_mirror_index != 0) {
                                fprintf(stderr,
                                        "%s %s: can't specify both mirror index and mirror ID\n",
@@ -5369,6 +5679,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
                        param->fp_check_mirror_id = 1;
                        param->fp_exclude_mirror_id = !!neg_opt;
                        break;
+               }
                case 'd':
                        param->fp_max_depth = 0;
                        break;
@@ -5394,6 +5705,9 @@ static int lfs_getstripe_internal(int argc, char **argv,
                                        rc = llapi_parse_size(tmp,
                                                &param->fp_comp_end,
                                                &param->fp_comp_end_units, 0);
+                                       /* assume units of KB if too small */
+                                       if (param->fp_comp_end < 4096)
+                                               param->fp_comp_end *= 1024;
                                }
                                if (rc != 0) {
                                        fprintf(stderr,
@@ -5680,13 +5994,14 @@ enum mntdf_flags {
        MNTDF_LAZY      = 0x0004,
        MNTDF_VERBOSE   = 0x0008,
        MNTDF_SHOW      = 0x0010,
+       MNTDF_DECIMAL   = 0x0020,
 };
 
-#define COOK(value)                                            \
+#define COOK(value, base)                                      \
 ({                                                             \
        int radix = 0;                                          \
-       while (value > 1024) {                                  \
-               value /= 1024;                                  \
+       while (value > base) {                                  \
+               value /= base;                                  \
                radix++;                                        \
        }                                                       \
        radix;                                                  \
@@ -5744,7 +6059,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat,
 {
        long long avail, used, total;
        int ratio = 0;
-       char *suffix = "KMGTPEZY";
+       char *suffix = flags & MNTDF_DECIMAL ? "kMGTPEZY" : "KMGTPEZY";
        /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
        char tbuf[3 * sizeof(__u64)];
        char ubuf[3 * sizeof(__u64)];
@@ -5772,11 +6087,12 @@ static int showdf(char *mntdir, struct obd_statfs *stat,
                ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
 
                if (flags & MNTDF_COOKED) {
-                       int i;
+                       int base = flags & MNTDF_DECIMAL ? 1000 : 1024;
                        double cook_val;
+                       int i;
 
                        cook_val = (double)total;
-                       i = COOK(cook_val);
+                       i = COOK(cook_val, base);
                        if (i > 0)
                                snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
                                         suffix[i - 1]);
@@ -5784,7 +6100,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat,
                                snprintf(tbuf, sizeof(tbuf), CDF, total);
 
                        cook_val = (double)used;
-                       i = COOK(cook_val);
+                       i = COOK(cook_val, base);
                        if (i > 0)
                                snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
                                         suffix[i - 1]);
@@ -5792,7 +6108,7 @@ static int showdf(char *mntdir, struct obd_statfs *stat,
                                snprintf(ubuf, sizeof(ubuf), CDF, used);
 
                        cook_val = (double)avail;
-                       i = COOK(cook_val);
+                       i = COOK(cook_val, base);
                        if (i > 0)
                                snprintf(abuf, sizeof(abuf), HDF, cook_val,
                                         suffix[i - 1]);
@@ -6023,7 +6339,7 @@ static int lfs_setdirstripe(int argc, char **argv)
        mode_t mode = S_IRWXU | S_IRWXG | S_IRWXO;
        mode_t previous_mode = 0;
        char *xattr = NULL;
-       __u32 type = LU_FOREIGN_TYPE_DAOS, flags = 0;
+       __u32 type = LU_FOREIGN_TYPE_SYMLINK, flags = 0;
        struct option long_opts[] = {
        { .val = 'c',   .name = "count",        .has_arg = required_argument },
        { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
@@ -6066,8 +6382,11 @@ static int lfs_setdirstripe(int argc, char **argv)
                        break;
                case 'c':
                case 'T':
+                       errno = 0;
                        lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' ||
+                           lsa.lsa_stripe_count < -1 ||
+                           lsa.lsa_stripe_count > LOV_MAX_STRIPE_COUNT) {
                                fprintf(stderr,
                                        "%s %s: invalid stripe count '%s'\n",
                                        progname, argv[0], optarg);
@@ -6095,18 +6414,31 @@ static int lfs_setdirstripe(int argc, char **argv)
                                                        optarg);
                                                return CMD_HELP;
                                        }
+                               } else if (type >= UINT32_MAX) {
+                                       fprintf(stderr,
+                                               "%s %s: invalid foreign type '%s'\n",
+                                               progname, argv[0], optarg);
+                                       return CMD_HELP;
                                }
                        }
                        foreign_mode = true;
                        break;
                case LFS_LAYOUT_FLAGS_OPT:
+                       errno = 0;
                        flags = strtoul(optarg, &end, 16);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' ||
+                           flags >= UINT32_MAX) {
                                fprintf(stderr,
-                                       "%s %s: bad flags '%s'\n",
+                                       "%s %s: invalid hex flags '%s'\n",
                                        progname, argv[0], optarg);
                                return CMD_HELP;
                        }
+                       if (!foreign_mode) {
+                               fprintf(stderr,
+                                       "%s %s: hex flags must be specified with --foreign option\n",
+                                       progname, argv[0]);
+                               return CMD_HELP;
+                       }
                        break;
 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
                case 't':
@@ -6195,10 +6527,9 @@ static int lfs_setdirstripe(int argc, char **argv)
 
        if (!delete && lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT &&
            lsa.lsa_stripe_count == LLAPI_LAYOUT_DEFAULT && !foreign_mode) {
-               fprintf(stderr,
-                       "%s %s: stripe offset and count must be specified\n",
-                       progname, argv[0]);
-               return CMD_HELP;
+               /* if no parameters set, create directory on least-used MDTs */
+               lsa.lsa_stripe_off = -1;
+               lsa.lsa_stripe_count = 1;
        }
 
        if (delete &&
@@ -6341,6 +6672,33 @@ static int lfs_rmentry(int argc, char **argv)
        return result;
 }
 
+static int lfs_unlink_foreign(int argc, char **argv)
+{
+       char *name;
+       int   index;
+       int   result = 0;
+
+       if (argc <= 1) {
+               fprintf(stderr, "error: %s: missing pathname\n",
+                       argv[0]);
+               return CMD_HELP;
+       }
+
+       index = 1;
+       name = argv[index];
+       while (name != NULL) {
+               result = llapi_unlink_foreign(name);
+               if (result) {
+                       fprintf(stderr,
+                               "error: %s: unlink foreign entry '%s' failed\n",
+                               argv[0], name);
+                       break;
+               }
+               name = argv[++index];
+       }
+       return result;
+}
+
 static int lfs_mv(int argc, char **argv)
 {
        struct lmv_user_md lmu = { LMV_USER_MAGIC };
@@ -6365,8 +6723,10 @@ static int lfs_mv(int argc, char **argv)
                                "warning: '-M' deprecated, use '--mdt-index' or '-m' instead\n");
 #endif
                case 'm':
+                       errno = 0;
                        lmu.lum_stripe_offset = strtoul(optarg, &end, 0);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' ||
+                           lmu.lum_stripe_offset >= UINT32_MAX) {
                                fprintf(stderr, "%s mv: bad MDT index '%s'\n",
                                        progname, optarg);
                                return CMD_HELP;
@@ -6424,18 +6784,21 @@ static int lfs_df(int argc, char **argv)
        int c, rc = 0, index = 0;
        char fsname[PATH_MAX] = "", *pool_name = NULL;
        struct option long_opts[] = {
-       { .val = 'h',   .name = "human-readable",
-                                               .has_arg = no_argument },
+       { .val = 'h',   .name = "human-readable", .has_arg = no_argument },
+       { .val = 'H',   .name = "si",           .has_arg = no_argument },
        { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
        { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
        { .val = 'p',   .name = "pool",         .has_arg = required_argument },
        { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
        { .name = NULL} };
 
-       while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
+       while ((c = getopt_long(argc, argv, "hHilp:v", long_opts, NULL)) != -1) {
                switch (c) {
                case 'h':
-                       flags |= MNTDF_COOKED;
+                       flags = (flags & ~MNTDF_DECIMAL) | MNTDF_COOKED;
+                       break;
+               case 'H':
+                       flags |= MNTDF_COOKED | MNTDF_DECIMAL;
                        break;
                case 'i':
                        flags |= MNTDF_INODES;
@@ -6732,14 +7095,15 @@ int lfs_setquota_times(int argc, char **argv, struct if_quotactl *qctl)
        { .val = 'p',   .name = "projid",       .has_arg = no_argument },
        { .val = 't',   .name = "times",        .has_arg = no_argument },
        { .val = 'u',   .name = "user",         .has_arg = no_argument },
-       { .val = 'o',   .name = "pool",         .has_arg = required_argument },
+       { .val = LFS_POOL_OPT,
+                       .name = "pool",         .has_arg = required_argument },
        { .name = NULL } };
        int qtype;
 
        qctl->qc_cmd  = LUSTRE_Q_SETINFO;
        qctl->qc_type = ALLQUOTA;
 
-       while ((c = getopt_long(argc, argv, "b:gi:ptuo:",
+       while ((c = getopt_long(argc, argv, "b:gi:ptu",
                                long_opts, NULL)) != -1) {
                switch (c) {
                case 'u':
@@ -6790,7 +7154,7 @@ quota_type:
                        break;
                case 't': /* Yes, of course! */
                        break;
-               case 'o':
+               case LFS_POOL_OPT:
                        if (lfs_verify_poolarg(optarg))
                                return -1;
                        fprintf(stdout,
@@ -6854,7 +7218,8 @@ int lfs_setquota(int argc, char **argv)
        { .val = 'P',   .name = "default-prj",  .has_arg = no_argument },
        { .val = 'u',   .name = "user",         .has_arg = required_argument },
        { .val = 'U',   .name = "default-usr",  .has_arg = no_argument },
-       { .val = 'o',   .name = "pool",         .has_arg = required_argument },
+       { .val = LFS_POOL_OPT,
+                       .name = "pool",         .has_arg = required_argument },
        { .name = NULL } };
        unsigned int limit_mask = 0;
        bool use_default = false;
@@ -6880,7 +7245,7 @@ int lfs_setquota(int argc, char **argv)
                                   * isn't reinitialized from command line
                                   */
 
-       while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:Uo:",
+       while ((c = getopt_long(argc, argv, "b:B:dg:Gi:I:p:Pu:U",
                long_opts, NULL)) != -1) {
                switch (c) {
                case 'U':
@@ -6989,7 +7354,7 @@ quota_type_def:
                                        (unsigned long long)dqb->dqb_ihardlimit,
                                        progname);
                        break;
-               case 'o':
+               case LFS_POOL_OPT:
                        if (lfs_verify_poolarg(optarg)) {
                                rc = -1;
                                goto out;
@@ -7324,16 +7689,39 @@ static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
        }
 }
 
+static int tgt_name2index(const char *tgtname, unsigned int *idx)
+{
+       char *dash, *endp;
+
+       /* format is "lustre-OST0001" */
+       dash = memchr(tgtname, '-', LUSTRE_MAXFSNAME + 1);
+       if (!dash) {
+               fprintf(stderr, "wrong tgtname format '%s'\n", tgtname);
+               return -EINVAL;
+       }
+       dash += 4;
+
+       *idx = strtoul(dash, &endp, 16);
+       if (*idx > 0xffff) {
+               fprintf(stderr, "wrong index %s\n", tgtname);
+               return -ERANGE;
+       }
+
+       return 0;
+}
+
 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
                           bool h, __u64 *total)
 {
-       int rc = 0, rc1 = 0, count = 0;
+       int rc = 0, rc1 = 0, count = 0, i = 0;
+       char **list = NULL, *buffer = NULL;
        __u32 valid = qctl->qc_valid;
 
-       /*
-        * TODO: for commands LUSTRE_Q_"S\|G"ETQUOTAPOOL we need
-        * to go only through OSTs that belong to requested pool.
-        */
+       if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL && is_mdt)
+               return 0;
+
+       /* Is it correct for the case OST0000, OST0002, OST0003 -
+        * we will ask OST0001 that is absent and won't ask OST0003? */
        rc = llapi_get_obd_count(mnt, &count, is_mdt);
        if (rc) {
                fprintf(stderr, "can not get %s count: %s\n",
@@ -7341,7 +7729,39 @@ static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
                return rc;
        }
 
-       for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
+       if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
+               char fname[PATH_MAX];
+               char fsname[LUSTRE_MAXFSNAME + 1];
+               int bufsize = sizeof(struct obd_uuid) * count;
+
+               rc = llapi_search_fsname(mnt, fsname);
+               if (rc) {
+                       fprintf(stderr, "cannot get fsname for mountpoint %s\n",
+                               mnt);
+                       goto out;
+               }
+               buffer = malloc(bufsize + sizeof(*list) * count);
+               if (!buffer)
+                       return -ENOMEM;
+               list = (char **)(buffer + bufsize);
+               snprintf(fname, PATH_MAX, "%s.%s", fsname, qctl->qc_poolname);
+               count = llapi_get_poolmembers(fname, list, count,
+                                             buffer, bufsize);
+               if (count <= 0)
+                       goto out;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL) {
+                       unsigned int index;
+
+                       if (tgt_name2index(list[i], &index))
+                               continue;
+                       qctl->qc_idx = index;
+               } else {
+                       qctl->qc_idx = i;
+               }
+
                qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
                rc = llapi_quotactl(mnt, qctl);
                if (rc) {
@@ -7364,6 +7784,8 @@ static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
                                   qctl->qc_dqblk.dqb_bhardlimit;
        }
 out:
+       if (buffer)
+               free(buffer);
        qctl->qc_valid = valid;
        return rc ? : rc1;
 }
@@ -7649,7 +8071,7 @@ static int lfs_quota(int argc, char **argv)
        bool show_default = false;
        int qtype;
        struct option long_opts[] = {
-       { .val = 1,     .name = "pool", .has_arg = required_argument },
+       { .val = LFS_POOL_OPT, .name = "pool", .has_arg = required_argument },
        { .name = NULL } };
 
        qctl = calloc(1, sizeof(*qctl) + LOV_MAXPOOLNAME + 1);
@@ -7725,7 +8147,7 @@ quota_type:
                case 'h':
                        human_readable = true;
                        break;
-               case 1:
+               case LFS_POOL_OPT:
                        if (lfs_verify_poolarg(optarg)) {
                                rc = -1;
                                goto out;
@@ -7853,16 +8275,19 @@ static int flushctx_ioctl(char *mp)
 
 static int lfs_flushctx(int argc, char **argv)
 {
-       int     kdestroy = 0, c;
+       int     kdestroy = 0, reap = 0, c;
        char    mntdir[PATH_MAX] = {'\0'};
        int     index = 0;
        int     rc = 0;
 
-       while ((c = getopt(argc, argv, "k")) != -1) {
+       while ((c = getopt(argc, argv, "kr")) != -1) {
                switch (c) {
                case 'k':
                        kdestroy = 1;
                        break;
+               case 'r':
+                       reap = 1;
+                       break;
                default:
                        fprintf(stderr,
                                "error: %s: option '-%c' unrecognized\n",
@@ -7900,6 +8325,15 @@ static int lfs_flushctx(int argc, char **argv)
                                rc = -1;
                }
        }
+
+       if (reap) {
+               rc = system("keyctl reap > /dev/null");
+               if (rc != 0) {
+                       rc = WEXITSTATUS(rc);
+                       fprintf(stderr, "error reaping keyring: %d\n", rc);
+               }
+       }
+
        return rc;
 }
 
@@ -7935,10 +8369,27 @@ static int lfs_changelog(int argc, char **argv)
        }
 
        mdd = argv[optind++];
-       if (argc > optind)
+       if (argc > optind) {
+               errno = 0;
                startrec = strtoll(argv[optind++], NULL, 10);
-       if (argc > optind)
+               if (errno != 0 || startrec < 0) {
+                       fprintf(stderr,
+                               "%s changelog: bad startrec\n",
+                               progname);
+                       return CMD_HELP;
+               }
+       }
+
+       if (argc > optind) {
+               errno = 0;
                endrec = strtoll(argv[optind++], NULL, 10);
+               if (errno != 0 || endrec < 0) {
+                       fprintf(stderr,
+                               "%s changelog: bad endrec\n",
+                               progname);
+                       return CMD_HELP;
+               }
+       }
 
        rc = llapi_changelog_start(&changelog_priv,
                                   CHANGELOG_FLAG_BLOCK |
@@ -8049,9 +8500,11 @@ static int lfs_changelog(int argc, char **argv)
                        }
                }
 
+               if (!fid_is_zero(&rec->cr_pfid))
+                       printf(" p="DFID, PFID(&rec->cr_pfid));
                if (rec->cr_namelen)
-                       printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
-                              rec->cr_namelen, changelog_rec_name(rec));
+                       printf(" %.*s", rec->cr_namelen,
+                              changelog_rec_name(rec));
 
                if (rec->cr_flags & CLF_RENAME) {
                        struct changelog_ext_rename *rnm =
@@ -8086,7 +8539,14 @@ static int lfs_changelog_clear(int argc, char **argv)
        if (argc != 4)
                return CMD_HELP;
 
+       errno = 0;
        endrec = strtoll(argv[3], NULL, 10);
+       if (errno != 0 || endrec < 0) {
+               fprintf(stderr,
+                       "%s: bad endrec '%s'\n",
+                       argv[0], argv[3]);
+               return CMD_HELP;
+       }
 
        rc = llapi_changelog_clear(argv[1], argv[2], endrec);
 
@@ -8106,32 +8566,49 @@ static int lfs_changelog_clear(int argc, char **argv)
        return rc;
 }
 
+static void rstripc(char *str, int c)
+{
+       char *end = str + strlen(str);
+
+       for (; str < end && end[-1] == c; --end)
+               end[-1] = '\0';
+}
+
 static int lfs_fid2path(int argc, char **argv)
 {
        struct option long_opts[] = {
                { .val = 'c',   .name = "cur",  .has_arg = no_argument },
+               { .val = 'c',   .name = "current",      .has_arg = no_argument },
+               { .val = 'c',   .name = "print-link",   .has_arg = no_argument },
+               { .val = 'f',   .name = "print-fid",    .has_arg = no_argument },
                { .val = 'l',   .name = "link", .has_arg = required_argument },
-               { .val = 'r',   .name = "rec",  .has_arg = required_argument },
                { .name = NULL } };
-       char short_opts[] = "cl:r:";
-       char mntdir[PATH_MAX];
-       char *device, *fid, *path, *rootpath;
+       char short_opts[] = "cfl:pr:";
+       bool print_link = false;
+       bool print_fid = false;
+       bool print_mnt_dir;
+       char mnt_dir[PATH_MAX] = "";
+       int mnt_fd = -1;
+       char *path_or_fsname;
        long long recno = -1;
        int linkno = -1;
-       int lnktmp;
-       int printcur = 0;
-       int rc = 0;
        char *endptr = NULL;
+       int rc = 0;
+       int c;
+       int i;
 
-       while ((rc = getopt_long(argc, argv, short_opts,
-               long_opts, NULL)) != -1) {
-               switch (rc) {
+       while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
+               switch (c) {
                case 'c':
-                       printcur++;
+                       print_link = true;
+                       break;
+               case 'f':
+                       print_fid = true;
                        break;
                case 'l':
+                       errno = 0;
                        linkno = strtol(optarg, &endptr, 10);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' || linkno < 0) {
                                fprintf(stderr,
                                        "%s fid2path: invalid linkno '%s'\n",
                                        progname, optarg);
@@ -8139,8 +8616,13 @@ static int lfs_fid2path(int argc, char **argv)
                        }
                        break;
                case 'r':
+                       /* recno is something to do with changelogs
+                        * that was never implemented. We just pass it
+                        * through for the MDT to ignore.
+                        */
+                       errno = 0;
                        recno = strtoll(optarg, &endptr, 10);
-                       if (*endptr != '\0') {
+                       if (errno != 0 || *endptr != '\0' || recno < 0) {
                                fprintf(stderr,
                                        "%s fid2path: invalid recno '%s'\n",
                                        progname, optarg);
@@ -8155,78 +8637,110 @@ static int lfs_fid2path(int argc, char **argv)
                }
        }
 
-       if (argc < 3) {
+       if (argc - optind < 2) {
                fprintf(stderr,
-                       "%s fid2path: <fsname|rootpath> and <fid>... must be specified\n",
+                       "Usage: %s fid2path FSNAME|ROOT FID...\n",
                        progname);
                return CMD_HELP;
        }
 
-       device = argv[optind++];
-       path = calloc(1, PATH_MAX);
-       if (!path) {
-               rc = -errno;
+       path_or_fsname = argv[optind];
+
+       if (*path_or_fsname == '/') {
+               print_mnt_dir = true;
+               rc = llapi_search_mounts(path_or_fsname, 0, mnt_dir, NULL);
+       } else {
+               print_mnt_dir = false;
+               rc = llapi_search_rootpath(mnt_dir, path_or_fsname);
+       }
+
+       if (rc < 0) {
                fprintf(stderr,
-                       "%s fid2path: cannot allocate memory for path: %s\n",
-                       progname, strerror(-rc));
-               return rc;
+                       "%s fid2path: cannot resolve mount point for '%s': %s\n",
+                       progname, path_or_fsname, strerror(-rc));
+               goto out;
        }
 
-       rc = 0;
-       /* in case that device is not the mountpoint */
-       if (device[0] == '/') {
-               rc = llapi_search_mounts(device, 0, mntdir, NULL);
-               if (rc == 0) {
-                       rootpath = mntdir;
-               } else {
+       mnt_fd = open(mnt_dir, O_RDONLY | O_DIRECTORY);
+       if (mnt_fd < 0) {
+               fprintf(stderr,
+                       "%s fid2path: cannot open mount point for '%s': %s\n",
+                       progname, path_or_fsname, strerror(-rc));
+               goto out;
+       }
+
+       /* Strip trailing slashes from mnt_dir. */
+       rstripc(mnt_dir + 1, '/');
+
+       for (i = optind + 1; i < argc; i++) {
+               const char *fid_str = argv[i];
+               struct lu_fid fid;
+               int rc2;
+
+               rc2 = llapi_fid_parse(fid_str, &fid, NULL);
+               if (rc2 < 0) {
                        fprintf(stderr,
-                               "%s fid2path: %s has no mountpoint: %s\n",
-                               progname, device, strerror(-rc));
-                       goto out;
+                               "%s fid2path: invalid FID '%s'\n",
+                               progname, fid_str);
+                       if (rc == 0)
+                               rc = rc2;
+
+                       continue;
                }
-       }
-       while (optind < argc) {
-               fid = argv[optind++];
 
-               lnktmp = (linkno >= 0) ? linkno : 0;
+               int linktmp = (linkno >= 0) ? linkno : 0;
                while (1) {
-                       int oldtmp = lnktmp;
+                       int oldtmp = linktmp;
                        long long rectmp = recno;
-                       int rc2;
+                       char path_buf[PATH_MAX];
 
-                       rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
-                                            &rectmp, &lnktmp);
+                       rc2 = llapi_fid2path_at(mnt_fd, &fid,
+                               path_buf, sizeof(path_buf), &rectmp, &linktmp);
                        if (rc2 < 0) {
                                fprintf(stderr,
                                        "%s fid2path: cannot find %s %s: %s\n",
-                                       progname, device, fid,
-                                       strerror(errno = -rc2));
+                                       progname, path_or_fsname, fid_str,
+                                       strerror(-rc2));
                                if (rc == 0)
                                        rc = rc2;
                                break;
                        }
 
-                       if (printcur)
-                               fprintf(stdout, "%lld ", rectmp);
-                       if (device[0] == '/') {
-                               fprintf(stdout, "%s", rootpath);
-                               if (rootpath[strlen(rootpath) - 1] != '/')
-                                       fprintf(stdout, "/");
-                       } else if (path[0] == '\0') {
-                               fprintf(stdout, "/");
-                       }
-                       fprintf(stdout, "%s\n", path);
+                       if (print_fid)
+                               printf("%s ", fid_str);
+
+                       if (print_link)
+                               printf("%d ", linktmp);
+
+                       /* You may think this looks wrong or weird (and it is!)
+                        * but we are actually trying to preserve the old quirky
+                        * behaviors (enforced by our old quirky tests!) that
+                        * make lfs so much fun to work on:
+                        *
+                        *   lustre 0x200000007:0x1:0x0 => "/"
+                        *   /mnt/lustre 0x200000007:0x1:0x0 => "/mnt/lustre//"
+                        *
+                        * Note that llapi_fid2path() returns "" for the root
+                        * FID. */
+
+                       printf("%s%s%s\n",
+                              print_mnt_dir ? mnt_dir : "",
+                              (print_mnt_dir || *path_buf == '\0') ? "/" : "",
+                              path_buf);
 
                        if (linkno >= 0)
                                /* specified linkno */
                                break;
-                       if (oldtmp == lnktmp)
+
+                       if (oldtmp == linktmp)
                                /* no more links */
                                break;
                }
        }
 out:
-       free(path);
+       if (!(mnt_fd < 0))
+               close(mnt_fd);
+
        return rc;
 }
 
@@ -8315,28 +8829,29 @@ static int lfs_path2fid(int argc, char **argv)
 
 static int lfs_rmfid_and_show_errors(const char *device, struct fid_array *fa)
 {
-       int rc, rc2 = 0, k;
+       int rc, rc2, k;
 
        rc = llapi_rmfid(device, fa);
-       if (rc) {
-               fprintf(stderr, "rmfid(): rc = %d\n", rc);
+       if (rc < 0) {
+               fprintf(stderr, "%s rmfid: cannot remove FIDs: %s\n",
+                       progname, strerror(-rc));
                return rc;
        }
 
        for (k = 0; k < fa->fa_nr; k++) {
-               rc = (__s32)fa->fa_fids[k].f_ver;
-               if (!IS_ERR_VALUE(rc))
-                       continue;
-               if (!rc2 && rc)
-                       rc2 = rc;
-               if (!rc)
+               rc2 = (__s32)fa->fa_fids[k].f_ver;
+               if (!IS_ERR_VALUE(rc2))
                        continue;
+
+               if (rc == 0)
+                       rc = rc2;
+
                fa->fa_fids[k].f_ver = 0;
-               fprintf(stderr, "rmfid("DFID"): rc = %d\n",
-                       PFID(&fa->fa_fids[k]), rc);
+               fprintf(stderr, "%s rmfid: cannot remove "DFID": %s\n",
+                       progname, PFID(&fa->fa_fids[k]), strerror(-rc2));
        }
 
-       return rc2;
+       return rc;
 }
 
 static int lfs_rmfid(int argc, char **argv)
@@ -8549,8 +9064,9 @@ static int lfs_hsm_change_flags(int argc, char **argv, int mode)
                        mask |= HS_EXISTS;
                        break;
                case 'i':
+                       errno = 0;
                        archive_id = strtol(optarg, &end, 10);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' || archive_id < 0) {
                                fprintf(stderr, "invalid archive_id: '%s'\n",
                                        end);
                                return CMD_HELP;
@@ -9844,15 +10360,22 @@ static inline int lfs_mirror_read(int argc, char **argv)
                char *end;
 
                switch (c) {
-               case 'N':
-                       mirror_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || mirror_id == 0) {
+               case 'N': {
+                       unsigned long int id;
+
+                       errno = 0;
+                       id = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' || id == 0 ||
+                           id > UINT16_MAX) {
                                fprintf(stderr,
                                        "%s %s: invalid mirror ID '%s'\n",
                                        progname, argv[0], optarg);
                                return rc;
                        }
+
+                       mirror_id = (__u16)id;
                        break;
+               }
                case 'o':
                        outfile = optarg;
                        break;
@@ -10000,15 +10523,22 @@ static inline int lfs_mirror_write(int argc, char **argv)
                char *end;
 
                switch (c) {
-               case 'N':
-                       mirror_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || mirror_id == 0) {
+               case 'N': {
+                       unsigned long int id;
+
+                       errno = 0;
+                       id = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' || id == 0 ||
+                           id > UINT16_MAX) {
                                fprintf(stderr,
                                        "%s %s: invalid mirror ID '%s'\n",
                                        progname, argv[0], optarg);
                                return rc;
                        }
+
+                       mirror_id = (__u16)id;
                        break;
+               }
                case 'i':
                        inputfile = optarg;
                        break;
@@ -10224,15 +10754,22 @@ static inline int lfs_mirror_copy(int argc, char **argv)
                char *end;
 
                switch (c) {
-               case 'i':
-                       read_mirror_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || read_mirror_id == 0) {
+               case 'i': {
+                       unsigned long int id;
+
+                       errno = 0;
+                       id = strtoul(optarg, &end, 0);
+                       if (errno != 0 || *end != '\0' || id == 0 ||
+                           id > UINT16_MAX) {
                                fprintf(stderr,
                                        "%s %s: invalid read mirror ID '%s'\n",
                                        progname, argv[0], optarg);
                                return rc;
                        }
+
+                       read_mirror_id = (__u16)id;
                        break;
+               }
                case 'o':
                        if (!strcmp(optarg, "-1")) {
                                /* specify all other mirrors */
@@ -11203,8 +11740,10 @@ static int lfs_pcc_attach(int argc, char **argv)
                                long_opts, NULL)) != -1) {
                switch (c) {
                case 'i':
+                       errno = 0;
                        archive_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0' || archive_id == 0) {
+                       if (errno != 0 || *end != '\0' ||
+                           archive_id == 0 || archive_id > UINT32_MAX) {
                                fprintf(stderr,
                                        "error: %s: bad archive ID '%s'\n",
                                        argv[0], optarg);
@@ -11275,8 +11814,10 @@ static int lfs_pcc_attach_fid(int argc, char **argv)
                                long_opts, NULL)) != -1) {
                switch (c) {
                case 'i':
+                       errno = 0;
                        archive_id = strtoul(optarg, &end, 0);
-                       if (*end != '\0') {
+                       if (errno != 0 || *end != '\0' ||
+                           archive_id > UINT32_MAX) {
                                fprintf(stderr,
                                        "error: %s: bad archive ID '%s'\n",
                                        argv[0], optarg);