Whamcloud - gitweb
LU-11466 mdt: Skip SOM xattr update for DoM-only files
[fs/lustre-release.git] / lustre / utils / lfs.c
index e21b059..57bc998 100644 (file)
@@ -124,7 +124,8 @@ static int lfs_mirror_list_commands(int argc, char **argv);
 static int lfs_list_commands(int argc, char **argv);
 static inline int lfs_mirror_resync(int argc, char **argv);
 static inline int lfs_mirror_verify(int argc, char **argv);
-static inline int lfs_mirror_dump(int argc, char **argv);
+static inline int lfs_mirror_read(int argc, char **argv);
+static inline int lfs_mirror_write(int argc, char **argv);
 
 enum setstripe_origin {
        SO_SETSTRIPE,
@@ -284,10 +285,14 @@ command_t mirror_cmdlist[] = {
        "\t             mirror will be stored into. If not specified,\n"
        "\t             a new file named <mirrored_file>.mirror~<mirror_id>\n"
        "\t             will be used.\n" },
-       { .pc_name = "dump", .pc_func = lfs_mirror_dump,
-         .pc_help = "Dump the content of a specified mirror of a file.\n"
-                 "usage: lfs mirror dump <--mirror-id|-N <mirror_id> "
-                 "[--outfile|-o <output_file>] <mirrored_file>\n" },
+       { .pc_name = "read", .pc_func = lfs_mirror_read,
+         .pc_help = "Read the content of a specified mirror of a file.\n"
+               "usage: lfs mirror read <--mirror-id|-N <mirror_id> "
+               "[--outfile|-o <output_file>] <mirrored_file>\n" },
+       { .pc_name = "write", .pc_func = lfs_mirror_write,
+         .pc_help = "Write to a specified mirror of a file.\n"
+               "usage: lfs mirror write <--mirror-id|-N <mirror_id> "
+               "[--inputfile|-i <input_file>] <mirrored_file>\n" },
        { .pc_name = "resync", .pc_func = lfs_mirror_resync,
          .pc_help = "Resynchronizes out-of-sync mirrored file(s).\n"
                "usage: lfs mirror resync [--only <mirror_id[,...]>] "
@@ -297,7 +302,7 @@ command_t mirror_cmdlist[] = {
                "usage: lfs mirror verify "
                "[--only <mirror_id,mirror_id2[,...]>] "
                "[--verbose|-v] <mirrored_file> [<mirrored_file2> ...]\n"},
-       { .pc_name = "--list-commands", .pc_func = lfs_mirror_list_commands,
+       { .pc_name = "list-commands", .pc_func = lfs_mirror_list_commands,
          .pc_help = "list commands supported by lfs mirror"},
        { .pc_name = "help", .pc_func = Parser_help, .pc_help = "help" },
        { .pc_name = "exit", .pc_func = Parser_quit, .pc_help = "quit" },
@@ -586,7 +591,8 @@ command_t cmdlist[] = {
         "lfs mirror extend - add mirror(s) to an existing file\n"
         "lfs mirror split  - split a mirror from an existing mirrored file\n"
         "lfs mirror resync - resynchronize out-of-sync mirrored file(s)\n"
-        "lfs mirror dump   - dump a mirror content of a mirrored file\n"
+        "lfs mirror read   - read a mirror content of a mirrored file\n"
+        "lfs mirror write  - write to a mirror of a mirrored file\n"
         "lfs mirror verify - verify mirrored file(s)\n"},
        {"getsom", lfs_getsom, 0, "To list the SOM info for a given file.\n"
         "usage: getsom [-s] [-b] [-f] <path>\n"
@@ -2255,59 +2261,64 @@ static int build_layout_from_yaml_node(struct cYAML *node,
        int rc = 0;
 
        while (node) {
-               string = node->cy_string;
-               /* skip leading lmm_ if present, to simplify parsing */
-               if (string != NULL && strncmp(string, "lmm_", 4) == 0)
-                       string += 4;
-
-               if (node->cy_type == CYAML_TYPE_STRING) {
-                       if (!strcmp(string, "lcme_extent.e_end")) {
-                               if (!strcmp(node->cy_valuestring, "EOF") ||
-                                   !strcmp(node->cy_valuestring, "eof"))
-                                       lsa->lsa_comp_end = LUSTRE_EOF;
-                       } else if (!strcmp(string, "pool")) {
-                               lsa->lsa_pool_name = node->cy_valuestring;
-                       } else if (!strcmp(string, "pattern")) {
-                               if (!strcmp(node->cy_valuestring, "mdt"))
-                                       lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
-                       }
-               } else if (node->cy_type == CYAML_TYPE_NUMBER) {
-                       if (!strcmp(string, "lcm_mirror_count")) {
-                               lsa->lsa_mirror_count = node->cy_valueint;
-                       } else if (!strcmp(string, "lcme_extent.e_start")) {
-                               if (node->cy_valueint != 0 || *layout != NULL) {
-                                       rc = build_component(layout, lsa, true);
-                                       if (rc)
-                                               return rc;
-                               }
-
-                               if (node->cy_valueint == 0)
-                                       lsa->lsa_first_comp = true;
-
-                               /* initialize lsa */
-                               setstripe_args_init(lsa);
-                               lsa->lsa_tgts = osts;
-                       } else if (!strcmp(string, "lcme_extent.e_end")) {
-                               if (node->cy_valueint == -1)
-                                       lsa->lsa_comp_end = LUSTRE_EOF;
-                               else
-                                       lsa->lsa_comp_end = node->cy_valueint;
-                       } else if (!strcmp(string, "stripe_count")) {
-                               lsa->lsa_stripe_count = node->cy_valueint;
-                       } else if (!strcmp(string, "stripe_size")) {
-                               lsa->lsa_stripe_size = node->cy_valueint;
-                       } else if (!strcmp(string, "stripe_offset")) {
-                               lsa->lsa_stripe_off = node->cy_valueint;
-                       } else if (!strcmp(string, "l_ost_idx")) {
-                               osts[lsa->lsa_nr_tgts] = node->cy_valueint;
-                               lsa->lsa_nr_tgts++;
-                       }
-               } else if (node->cy_type == CYAML_TYPE_OBJECT) {
+               if (node->cy_type == CYAML_TYPE_OBJECT) {
                        /* go deep to sub blocks */
                        rc = build_layout_from_yaml_node(node->cy_child, layout,
                                                         lsa, osts);
                        if (rc)
                                return rc;
+               } else {
+                       if (node->cy_string == NULL)
+                               return -EINVAL;
+
+                       string = node->cy_string;
+                       /* skip leading lmm_ if present, to simplify parsing */
+                       if (strncmp(string, "lmm_", 4) == 0)
+                               string += 4;
+
+                       if (node->cy_type == CYAML_TYPE_STRING) {
+                               if (!strcmp(string, "lcme_extent.e_end")) {
+                                       if (!strcmp(node->cy_valuestring, "EOF") ||
+                                           !strcmp(node->cy_valuestring, "eof"))
+                                               lsa->lsa_comp_end = LUSTRE_EOF;
+                               } else if (!strcmp(string, "pool")) {
+                                       lsa->lsa_pool_name = node->cy_valuestring;
+                               } else if (!strcmp(string, "pattern")) {
+                                       if (!strcmp(node->cy_valuestring, "mdt"))
+                                               lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
+                               }
+                       } else if (node->cy_type == CYAML_TYPE_NUMBER) {
+                               if (!strcmp(string, "lcm_mirror_count")) {
+                                       lsa->lsa_mirror_count = node->cy_valueint;
+                               } else if (!strcmp(string, "lcme_extent.e_start")) {
+                                       if (node->cy_valueint != 0 || *layout != NULL) {
+                                               rc = build_component(layout, lsa, true);
+                                               if (rc)
+                                                       return rc;
+                                       }
+
+                                       if (node->cy_valueint == 0)
+                                               lsa->lsa_first_comp = true;
+
+                                       /* initialize lsa */
+                                       setstripe_args_init(lsa);
+                                       lsa->lsa_tgts = osts;
+                               } else if (!strcmp(string, "lcme_extent.e_end")) {
+                                       if (node->cy_valueint == -1)
+                                               lsa->lsa_comp_end = LUSTRE_EOF;
+                                       else
+                                               lsa->lsa_comp_end = node->cy_valueint;
+                               } else if (!strcmp(string, "stripe_count")) {
+                                       lsa->lsa_stripe_count = node->cy_valueint;
+                               } else if (!strcmp(string, "stripe_size")) {
+                                       lsa->lsa_stripe_size = node->cy_valueint;
+                               } else if (!strcmp(string, "stripe_offset")) {
+                                       lsa->lsa_stripe_off = node->cy_valueint;
+                               } else if (!strcmp(string, "l_ost_idx")) {
+                                       osts[lsa->lsa_nr_tgts] = node->cy_valueint;
+                                       lsa->lsa_nr_tgts++;
+                               }
+                       }
                }
                node = node->cy_next;
        }
@@ -2572,6 +2583,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
        char *template = NULL;
 
        struct option long_opts[] = {
+/* find { .val = '0',  .name = "null",         .has_arg = no_argument }, */
 /* find        { .val = 'A',   .name = "atime",        .has_arg = required_argument }*/
        /* --block is only valid in migrate mode */
        { .val = 'b',   .name = "block",        .has_arg = no_argument },
@@ -2616,6 +2628,7 @@ static int lfs_setstripe_internal(int argc, char **argv,
 /* find        { .val = 'F',   .name = "fid",          .has_arg = no_argument }, */
 /* find        { .val = 'g',   .name = "gid",          .has_arg = no_argument }, */
 /* find        { .val = 'G',   .name = "group",        .has_arg = required_argument }*/
+/* find        { .val = 'h',   .name = "help",         .has_arg = no_argument }, */
        { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument},
        { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
        { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
@@ -4121,6 +4134,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
        { .val = 'm',   .name = "mdt_index",    .has_arg = no_argument },
 /* find        { .val = 'M',   .name = "mtime",        .has_arg = required_argument }*/
 /* find        { .val = 'n',   .name = "name",         .has_arg = required_argument }*/
+       { .val = 'N',   .name = "mirror-count", .has_arg = no_argument },
        { .val = 'O',   .name = "obd",          .has_arg = required_argument },
        { .val = 'O',   .name = "ost",          .has_arg = required_argument },
        { .val = 'p',   .name = "pool",         .has_arg = no_argument },
@@ -4144,7 +4158,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
        char *end, *tmp;
 
        while ((c = getopt_long(argc, argv,
-                       "-cdDE::FghiI::LmMoO:pqrRsSvy",
+                       "-cdDE::FghiI::LmMNoO:pqrRsSvy",
                        long_opts, NULL)) != -1) {
                if (neg_opt)
                        --neg_opt;
@@ -4325,7 +4339,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
                        break;
                case 'i':
                        if (!(param->fp_verbose & VERBOSE_DETAIL)) {
-                               param->fp_verbose |= VERBOSE_OFFSET;
+                               param->fp_verbose |= VERBOSE_STRIPE_OFFSET;
                                param->fp_max_depth = 0;
                        }
                        break;
@@ -4348,7 +4362,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
                        break;
                case 'L':
                        if (!(param->fp_verbose & VERBOSE_DETAIL)) {
-                               param->fp_verbose |= VERBOSE_LAYOUT;
+                               param->fp_verbose |= VERBOSE_PATTERN;
                                param->fp_max_depth = 0;
                        }
                        break;
@@ -4362,6 +4376,12 @@ static int lfs_getstripe_internal(int argc, char **argv,
                                param->fp_max_depth = 0;
                        param->fp_verbose |= VERBOSE_MDTINDEX;
                        break;
+               case 'N':
+                       if (!(param->fp_verbose & VERBOSE_DETAIL)) {
+                               param->fp_verbose |= VERBOSE_MIRROR_COUNT;
+                               param->fp_max_depth = 0;
+                       }
+                       break;
                case 'O':
                        if (param->fp_obd_uuid) {
                                fprintf(stderr,
@@ -4388,7 +4408,7 @@ static int lfs_getstripe_internal(int argc, char **argv,
                        break;
                case 'S':
                        if (!(param->fp_verbose & VERBOSE_DETAIL)) {
-                               param->fp_verbose |= VERBOSE_SIZE;
+                               param->fp_verbose |= VERBOSE_STRIPE_SIZE;
                                param->fp_max_depth = 0;
                        }
                        break;
@@ -4513,7 +4533,7 @@ static int lfs_getdirstripe(int argc, char **argv)
                        break;
                case 'i':
                case 'm':
-                       param.fp_verbose |= VERBOSE_OFFSET;
+                       param.fp_verbose |= VERBOSE_STRIPE_OFFSET;
                        break;
 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
                case 't':
@@ -4770,6 +4790,8 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
        }
 
        for (tp = types; tp->st_name != NULL; tp++) {
+               bool have_ost = false;
+
                if (!(tp->st_op & ops))
                        continue;
 
@@ -4791,6 +4813,20 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
                                rc = rc2;
                        }
 
+                       /* If we have OSTs then don't report MDT block counts.
+                        * For MDT-only filesystems the expectation is that all
+                        * layouts have a DoM component.  For filesystems with
+                        * OSTs, files are not necessarily going to store data
+                        * on MDTs, and MDT space is limited to a fraction of
+                        * OST space, so don't include it in the summary.
+                        */
+                       if (tp->st_op == LL_STATFS_LOV && !have_ost) {
+                               have_ost = true;
+                               sum.os_blocks = 0;
+                               sum.os_bfree = 0;
+                               sum.os_bavail = 0;
+                       }
+
                        if (poolname && tp->st_op == LL_STATFS_LOV &&
                            llapi_search_ost(fsname, poolname,
                                             obd_uuid2str(&uuid_buf)) != 1)
@@ -4814,20 +4850,21 @@ static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags,
                                       obd_uuid2str(&uuid_buf), flags,
                                       tp->st_name, index, rc2);
 
-                       if (rc2 == 0) {
-                               if (tp->st_op == LL_STATFS_LMV) {
-                                       sum.os_ffree += stat_buf.os_ffree;
-                                       sum.os_files += stat_buf.os_files;
-                               } else /* if (tp->st_op == LL_STATFS_LOV) */ {
-                                       sum.os_blocks += stat_buf.os_blocks *
-                                               stat_buf.os_bsize;
-                                       sum.os_bfree  += stat_buf.os_bfree *
-                                               stat_buf.os_bsize;
-                                       sum.os_bavail += stat_buf.os_bavail *
-                                               stat_buf.os_bsize;
-                                       ost_ffree += stat_buf.os_ffree;
-                               }
+                       if (rc2)
+                               continue;
+
+                       if (tp->st_op == LL_STATFS_LMV) {
+                               sum.os_ffree += stat_buf.os_ffree;
+                               sum.os_files += stat_buf.os_files;
+                       } else /* if (tp->st_op == LL_STATFS_LOV) */ {
+                               ost_ffree += stat_buf.os_ffree;
                        }
+                       sum.os_blocks += stat_buf.os_blocks *
+                                        stat_buf.os_bsize;
+                       sum.os_bfree  += stat_buf.os_bfree *
+                                        stat_buf.os_bsize;
+                       sum.os_bavail += stat_buf.os_bavail *
+                                        stat_buf.os_bsize;
                }
        }
 
@@ -8257,7 +8294,7 @@ static inline int lfs_mirror_resync(int argc, char **argv)
                /* ignore previous file's error, continue with next file */
 
                /* reset ioc */
-               memset(ioc, 0, sizeof(__u32) * 4096);
+               memset(ioc, 0, sizeof(*ioc) + sizeof(__u32) * 4096);
        }
 
        free(ioc);
@@ -8265,21 +8302,76 @@ error:
        return rc;
 }
 
-static inline int lfs_mirror_dump(int argc, char **argv)
+static inline int verify_mirror_id_by_fd(int fd, __u16 mirror_id)
+{
+       struct llapi_layout *layout;
+       int rc;
+
+       layout = llapi_layout_get_by_fd(fd, 0);
+       if (layout == NULL) {
+               fprintf(stderr, "could not get layout.\n");
+               return  -EINVAL;
+       }
+
+       rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
+       if (rc < 0) {
+               fprintf(stderr, "failed to iterate layout\n");
+               llapi_layout_free(layout);
+
+               return rc;
+       } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
+               fprintf(stderr, "does not find mirror with ID %u\n", mirror_id);
+               llapi_layout_free(layout);
+
+               return -EINVAL;
+       }
+       llapi_layout_free(layout);
+
+       return 0;
+}
+
+/**
+ * Check whether two files are the same file
+ * \retval     0  same file
+ * \retval     1  not the same file
+ * \retval     <0 error code
+ */
+static inline int check_same_file(const char *f1, const char *f2)
+{
+       struct stat stbuf1;
+       struct stat stbuf2;
+
+       if (stat(f1, &stbuf1) < 0) {
+               fprintf(stderr, "%s: cannot stat file '%s': %s\n",
+                       progname, f1, strerror(errno));
+               return -errno;
+       }
+
+       if (stat(f2, &stbuf2) < 0) {
+               fprintf(stderr, "%s: cannot stat file '%s': %s\n",
+                       progname, f2, strerror(errno));
+               return -errno;
+       }
+
+       if (stbuf1.st_rdev == stbuf2.st_rdev &&
+           stbuf1.st_ino == stbuf2.st_ino)
+               return 0;
+
+       return 1;
+}
+
+static inline int lfs_mirror_read(int argc, char **argv)
 {
        int rc = CMD_HELP;
        __u16 mirror_id = 0;
        const char *outfile = NULL;
        char *fname;
-       struct stat stbuf;
        int fd = 0;
-       struct llapi_layout *layout;
        int outfd;
        int c;
-       const size_t buflen = 4 << 20;
        void *buf;
+       const size_t buflen = 4 << 20;
        off_t pos;
-
        struct option long_opts[] = {
        { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
        { .val = 'o',   .name = "outfile",      .has_arg = required_argument },
@@ -8301,6 +8393,10 @@ static inline int lfs_mirror_dump(int argc, char **argv)
                case 'o':
                        outfile = optarg;
                        break;
+               default:
+                       fprintf(stderr, "%s: option '%s' unrecognized.\n",
+                               progname, argv[optind - 1]);
+                       return -EINVAL;
                }
        }
 
@@ -8322,56 +8418,39 @@ static inline int lfs_mirror_dump(int argc, char **argv)
        /* open mirror file */
        fname = argv[optind];
 
-       if (stat(fname, &stbuf) < 0) {
-               fprintf(stderr, "%s %s: cannot stat file '%s': %s.\n",
-                       progname, argv[0], fname, strerror(errno));
-               return rc;
-       }
-
-       if (!S_ISREG(stbuf.st_mode)) {
-               fprintf(stderr, "%s %s: '%s' is not a regular file.\n",
-                       progname, argv[0], fname);
-               return rc;
+       if (outfile) {
+               rc = check_same_file(fname, outfile);
+               if (rc == 0) {
+                       fprintf(stderr,
+                       "%s %s: output file cannot be the mirrored file\n",
+                               progname, argv[0]);
+                       return -EINVAL;
+               }
+               if (rc < 0)
+                       return rc;
        }
 
        fd = open(fname, O_DIRECT | O_RDONLY);
        if (fd < 0) {
-               fprintf(stderr, "%s %s: cannot open '%s': %s.\n",
+               fprintf(stderr, "%s %s: cannot open '%s': %s\n",
                        progname, argv[0], fname, strerror(errno));
                return rc;
        }
 
        /* verify mirror id */
-       layout = llapi_layout_get_by_fd(fd, 0);
-       if (layout == NULL) {
-               fprintf(stderr, "%s %s: could not get layout of file '%s'.\n",
-                       progname, argv[0], fname);
-               rc = -EINVAL;
-               goto close_fd;
-       }
-
-       rc = llapi_layout_comp_iterate(layout, find_mirror_id, &mirror_id);
-       if (rc < 0) {
-               fprintf(stderr, "%s %s: failed to iterate layout of '%s'.\n",
-                       progname, argv[0], fname);
-               llapi_layout_free(layout);
-               goto close_fd;
-       } else if (rc == LLAPI_LAYOUT_ITER_CONT) {
+       rc = verify_mirror_id_by_fd(fd, mirror_id);
+       if (rc) {
                fprintf(stderr,
-                       "%s %s: file '%s' does not contain mirror with ID %u\n",
-                       progname, argv[0], fname, mirror_id);
-               llapi_layout_free(layout);
-
-               rc = -EINVAL;
+                       "%s %s: cannot find mirror with ID %u in '%s'\n",
+                       progname, argv[0], mirror_id, fname);
                goto close_fd;
        }
-       llapi_layout_free(layout);
 
        /* open output file */
        if (outfile) {
                outfd = open(outfile, O_EXCL | O_WRONLY | O_CREAT, 0644);
                if (outfd < 0) {
-                       fprintf(stderr, "%s %s: cannot create file '%s':%s.\n",
+                       fprintf(stderr, "%s %s: cannot create file '%s': %s\n",
                                progname, argv[0], outfile, strerror(errno));
                        rc = -errno;
                        goto close_fd;
@@ -8383,7 +8462,7 @@ static inline int lfs_mirror_dump(int argc, char **argv)
        /* allocate buffer */
        rc = posix_memalign(&buf, sysconf(_SC_PAGESIZE), buflen);
        if (rc) {
-               fprintf(stderr, "%s %s: posix_memalign returns %d.\n",
+               fprintf(stderr, "%s %s: posix_memalign returns %d\n",
                                progname, argv[0], rc);
                goto close_outfd;
        }
@@ -8397,7 +8476,7 @@ static inline int lfs_mirror_dump(int argc, char **argv)
                if (bytes_read < 0) {
                        rc = bytes_read;
                        fprintf(stderr,
-                               "%s %s: fail to read data from mirror %u:%s.\n",
+                               "%s %s: fail to read data from mirror %u: %s\n",
                                progname, argv[0], mirror_id, strerror(-rc));
                        goto free_buf;
                }
@@ -8413,7 +8492,7 @@ static inline int lfs_mirror_dump(int argc, char **argv)
                                         bytes_read - written);
                        if (written2 < 0) {
                                fprintf(stderr,
-                                       "%s %s: fail to write %s:%s.\n",
+                                       "%s %s: fail to write %s: %s\n",
                                        progname, argv[0], outfile ? : "STDOUT",
                                        strerror(errno));
                                rc = -errno;
@@ -8447,6 +8526,205 @@ close_fd:
        return rc;
 }
 
+static inline int lfs_mirror_write(int argc, char **argv)
+{
+       int rc = CMD_HELP;
+       __u16 mirror_id = 0;
+       const char *inputfile = NULL;
+       char *fname;
+       int fd = 0;
+       int inputfd;
+       int c;
+       void *buf;
+       const size_t buflen = 4 << 20;
+       off_t pos;
+       size_t page_size = sysconf(_SC_PAGESIZE);
+       struct ll_ioc_lease_id ioc;
+
+       struct option long_opts[] = {
+       { .val = 'N',   .name = "mirror-id",    .has_arg = required_argument },
+       { .val = 'i',   .name = "inputfile",    .has_arg = required_argument },
+       { .name = NULL } };
+
+       while ((c = getopt_long(argc, argv, "N:i:", long_opts, NULL)) >= 0) {
+               char *end;
+
+               switch (c) {
+               case 'N':
+                       mirror_id = strtoul(optarg, &end, 0);
+                       if (*end != '\0' || mirror_id == 0) {
+                               fprintf(stderr,
+                                       "%s %s: invalid mirror ID '%s'\n",
+                                       progname, argv[0], optarg);
+                               return rc;
+                       }
+                       break;
+               case 'i':
+                       inputfile = optarg;
+                       break;
+               default:
+                       fprintf(stderr, "%s: option '%s' unrecognized\n",
+                               progname, argv[optind - 1]);
+                       return -EINVAL;
+               }
+       }
+
+       if (argc == optind) {
+               fprintf(stderr, "%s %s: no mirrored file provided\n",
+                       progname, argv[0]);
+               return rc;
+       } else if (argc > optind + 1) {
+               fprintf(stderr, "%s %s: too many files\n", progname, argv[0]);
+               return rc;
+       }
+
+       if (mirror_id == 0) {
+               fprintf(stderr, "%s %s: no valid mirror ID is provided\n",
+                       progname, argv[0]);
+               return rc;
+       }
+
+       /* open mirror file */
+       fname = argv[optind];
+
+       if (inputfile) {
+               rc = check_same_file(fname, inputfile);
+               if (rc == 0) {
+                       fprintf(stderr,
+                       "%s %s: input file cannot be the mirrored file\n",
+                               progname, argv[0]);
+                       return -EINVAL;
+               }
+               if (rc < 0)
+                       return rc;
+       }
+
+       fd = open(fname, O_DIRECT | O_WRONLY);
+       if (fd < 0) {
+               fprintf(stderr, "%s %s: cannot open '%s': %s\n",
+                       progname, argv[0], fname, strerror(errno));
+               return rc;
+       }
+
+       /* verify mirror id */
+       rc = verify_mirror_id_by_fd(fd, mirror_id);
+       if (rc) {
+               fprintf(stderr,
+                       "%s %s: cannot find mirror with ID %u in '%s'\n",
+                       progname, argv[0], mirror_id, fname);
+               goto close_fd;
+       }
+
+       /* open input file */
+       if (inputfile) {
+               inputfd = open(inputfile, O_RDONLY, 0644);
+               if (inputfd < 0) {
+                       fprintf(stderr, "%s %s: cannot open file '%s': %s\n",
+                               progname, argv[0], inputfile, strerror(errno));
+                       rc = -errno;
+                       goto close_fd;
+               }
+       } else {
+               inputfd = STDIN_FILENO;
+       }
+
+       /* allocate buffer */
+       rc = posix_memalign(&buf, page_size, buflen);
+       if (rc) {
+               fprintf(stderr, "%s %s: posix_memalign returns %d\n",
+                       progname, argv[0], rc);
+               goto close_inputfd;
+       }
+
+       /* prepare target mirror components instantiation */
+       ioc.lil_mode = LL_LEASE_WRLCK;
+       ioc.lil_flags = LL_LEASE_RESYNC;
+       ioc.lil_mirror_id = mirror_id;
+       rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
+       if (rc < 0) {
+               fprintf(stderr,
+                       "%s %s: '%s' llapi_lease_get_ext failed: %s\n",
+                       progname, argv[0], fname, strerror(errno));
+               goto free_buf;
+       }
+
+       pos = 0;
+       while (1) {
+               ssize_t bytes_read;
+               ssize_t written;
+               size_t to_write;
+
+               rc = llapi_lease_check(fd);
+               if (rc != LL_LEASE_WRLCK) {
+                       fprintf(stderr, "%s %s: '%s' lost lease lock\n",
+                               progname, argv[0], fname);
+                       goto free_buf;
+               }
+
+               bytes_read = read(inputfd, buf, buflen);
+               if (bytes_read < 0) {
+                       rc = bytes_read;
+                       fprintf(stderr,
+                               "%s %s: fail to read data from '%s': %s\n",
+                               progname, argv[0], inputfile ? : "STDIN",
+                               strerror(errno));
+                       rc = -errno;
+                       goto free_buf;
+               }
+
+               /* EOF reached */
+               if (bytes_read == 0)
+                       break;
+
+               /* round up to page align to make direct IO happy. */
+               to_write = (bytes_read + page_size - 1) & ~(page_size - 1);
+
+               written = llapi_mirror_write(fd, mirror_id, buf, to_write,
+                                            pos);
+               if (written < 0) {
+                       rc = written;
+                       fprintf(stderr,
+                             "%s %s: fail to write to mirror %u: %s\n",
+                               progname, argv[0], mirror_id,
+                               strerror(-rc));
+                       goto free_buf;
+               }
+
+               pos += bytes_read;
+       }
+
+       if (pos & (page_size - 1)) {
+               rc = llapi_mirror_truncate(fd, mirror_id, pos);
+               if (rc < 0)
+                       goto free_buf;
+       }
+
+       ioc.lil_mode = LL_LEASE_UNLCK;
+       ioc.lil_flags = LL_LEASE_RESYNC_DONE;
+       ioc.lil_count = 0;
+       rc = llapi_lease_set(fd, (struct ll_ioc_lease *)&ioc);
+       if (rc <= 0) {
+               if (rc == 0)
+                       rc = -EBUSY;
+               fprintf(stderr,
+                       "%s %s: release lease lock of '%s' failed: %s\n",
+                       progname, argv[0], fname, strerror(errno));
+               goto free_buf;
+       }
+
+       rc = 0;
+
+free_buf:
+       free(buf);
+close_inputfd:
+       if (inputfile)
+               close(inputfd);
+close_fd:
+       close(fd);
+
+       return rc;
+}
+
 /**
  * struct verify_chunk - Mirror chunk to be verified.
  * @chunk:        [start, end) of the chunk.
@@ -9043,7 +9321,7 @@ static inline int lfs_mirror_verify(int argc, char **argv)
                        verbose++;
                        break;
                default:
-                       fprintf(stderr, "%s: options '%s' unrecognized.\n",
+                       fprintf(stderr, "%s: option '%s' unrecognized.\n",
                                progname, argv[optind - 1]);
                        rc = -EINVAL;
                        goto error;
@@ -9169,8 +9447,9 @@ static int lfs_getsom(int argc, char **argv)
        attrs = (void *)buf;
        rc = lgetxattr(path, "trusted.som", attrs, sizeof(buf));
        if (rc < 0) {
-               fprintf(stderr, "%s failed to get som xattr: %s\n", argv[0],
-                       strerror(-rc));
+               rc = -errno;
+               fprintf(stderr, "%s failed to get som xattr: %s (%d)\n",
+                       argv[0], strerror(errno), errno);
                return rc;
        }