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,
#define MIGRATE_USAGE \
SSM_CMD_COMMON("migrate ") \
- " [--block|-b]\n" \
- " [--non-block|-n]\n" \
- " [--non-direct|-D]\n" \
+ " [--block|-b] [--non-block|-n]\n" \
+ " [--non-direct|-D] [--verbose|-v]\n" \
" <filename>\n" \
SSM_HELP_COMMON \
"\n" \
"\tblock: Block file access during data migration (default)\n" \
"\tnon-block: Abort migrations if concurrent access is detected\n" \
- "\tnon-direct: Do not use direct I/O to copy file contents\n" \
+ "\tnon-direct: Do not use direct I/O to copy file contents\n" \
+ "\tverbose: Print each filename as it is migrated\n" \
#define SETDIRSTRIPE_USAGE \
" [--mdt-count|-c stripe_count>\n" \
- " [--mdt-index|-i mdt_index[,mdt_index,...]\n" \
" [--mdt-hash|-H mdt_hash]\n" \
- " [--default|-D] [--mode|-m mode] <dir>\n" \
+ " [--mdt-index|-i mdt_index[,mdt_index,...]\n" \
+ " [--default|-D] [--mode|-o mode] <dir>\n" \
"\tstripe_count: stripe count of the striped directory\n" \
"\tmdt_index: MDT index of first stripe\n" \
"\tmdt_hash: hash type of the striped directory. mdt types:\n" \
" fnv_1a_64 FNV-1a hash algorithm (default)\n" \
" all_char sum of characters % MDT_COUNT (not recommended)\n" \
"\tdefault_stripe: set default dirstripe of the directory\n" \
- "\tmode: the mode of the directory\n"
+ "\tmode: the file access permission of the directory (octal)\n"
/**
* command_t mirror_cmdlist - lfs mirror commands.
"\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[,...]>] "
"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" },
"usage: find <directory|filename> ...\n"
" [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
" [[!] --mtime|-M [+-]N] [--maxdepth|-D N] [[!] --blocks|-b N]\n"
- " [[!] --mdt-index|--mdt|-m <uuid|index,...>]\n"
" [[!] --name|-n <pattern>] [[!] --ost|-O <uuid|index,...>]\n"
" [--print|-P] [--print0|-0] [[!] --size|-s [+-]N[bkMGTPE]]\n"
" [[!] --stripe-count|-c [+-]<stripes>]\n"
" [[!] --mirror-state <[^]state>]\n"
" [[!] --mdt-count|-T [+-]<stripes>]\n"
" [[!] --mdt-hash|-H <hashtype>\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"
"\t fnv_1a_64 FNV-1a hash algorithm\n"
"\t all_char sum of characters % MDT_COUNT\n"},
{"check", lfs_check, 0,
- "Display the status of MDS or OSTs (as specified in the command)\n"
- "or all the servers (MDS and OSTs).\n"
- "usage: check <osts|mds|servers>"},
+ "Display the status of MGTs, MDTs or OSTs (as specified in the command)\n"
+ "or all the servers (MGTs, MDTs and OSTs).\n"
+ "usage: check <mgts|osts|mdts|all>"},
{"osts", lfs_osts, 0, "list OSTs connected to client "
"[for specified path only]\n" "usage: osts [path]"},
{"mdts", lfs_mdts, 0, "list MDTs connected to client "
"usage: swap_layouts <path1> <path2>"},
{"migrate", lfs_setstripe_migrate, 0,
"migrate a directory between MDTs.\n"
- "usage: migrate [--mdt|-m] <start_mdt_index>\n"
- " [--mdt-count|-c] <stripe_count>\n"
+ "usage: migrate [--mdt-count|-c] <stripe_count>\n"
" [--mdt-hash|-H] <hash_type>\n"
+ " [--mdt-index|-m] <start_mdt_index>\n"
" [--verbose|-v]\n"
" <directory>\n"
"\tmdt: MDTs to stripe over, if only one MDT is specified\n"
"\tstripe_size: number of bytes to store before moving to the next OST\n"
"\tpool_name: name of the predefined pool of OSTs\n"
"\tost_indices: OSTs to stripe over, in order\n"
- "\tblock: wait for the operation to return before continuing\n"
- "\tnon-block: do not wait for the operation to return\n"
+ "\tblock: Block file access during data migration (default)\n"
+ "\tnon-block: Abort migrations if concurrent access is detected\n"
"\tnon-direct: do not use direct I/O to copy file contents.\n"},
{"mv", lfs_mv, 0,
"To move directories between MDTs. This command is deprecated, "
"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"
static const char *error_loc = "syserror";
enum {
- MIGRATION_NONBLOCK = 1 << 0,
- MIGRATION_MIRROR = 1 << 1,
- MIGRATION_NONDIRECT = 1 << 2,
+ MIGRATION_NONBLOCK = 0x0001,
+ MIGRATION_MIRROR = 0x0002,
+ MIGRATION_NONDIRECT = 0x0004,
+ MIGRATION_VERBOSE = 0x0008,
};
static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
if (rc < 0)
fprintf(stderr, "error: %s: %s: %s: %s\n",
progname, name, error_loc, strerror(-rc));
+ else if (migration_flags & MIGRATION_VERBOSE)
+ printf("%s\n", name);
+
return rc;
}
} else if (!strcmp(string, "pattern")) {
if (!strcmp(node->cy_valuestring, "mdt"))
lsa->lsa_pattern = LLAPI_LAYOUT_MDT;
+ } else if (!strcmp(string, "lcme_flags")) {
+ rc = comp_str2flags(node->cy_valuestring,
+ &lsa->lsa_comp_flags,
+ &lsa->lsa_comp_neg_flags);
+ if (rc)
+ return rc;
+ /* Only template flags have meaning in
+ * the layout for a new file
+ */
+ lsa->lsa_comp_flags &= LCME_TEMPLATE_FLAGS;
}
} else if (node->cy_type == CYAML_TYPE_NUMBER) {
if (!strcmp(string, "lcm_mirror_count")) {
case 'm':
if (!migrate_mode) {
fprintf(stderr,
- "%s %s: -m|--mdt is valid only for migrate command\n",
+ "%s %s: -m|--mdt-index is valid only for migrate command\n",
progname, argv[0]);
goto usage_error;
}
goto usage_error;
}
migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
+ migration_flags = MIGRATION_VERBOSE;
break;
case 'y':
from_yaml = true;
#define RSF "%4s"
#define RDF "%3d%%"
-static inline int obd_statfs_ratio(const struct obd_statfs *st)
+static inline int obd_statfs_ratio(const struct obd_statfs *st, bool inodes)
{
double avail, used, ratio = 0;
- avail = st->os_bavail;
- used = st->os_blocks - st->os_bfree;
+ if (inodes) {
+ avail = st->os_ffree;
+ used = st->os_files - st->os_ffree;
+ } else {
+ avail = st->os_bavail;
+ used = st->os_blocks - st->os_bfree;
+ }
if (avail + used > 0)
- ratio = used / (used + avail) * 100 + 0.5;
+ ratio = used / (used + avail) * 100;
- return (int)ratio;
+ /* Round up to match df(1) usage percentage */
+ return (ratio - (int)ratio) > 0 ? (int)(ratio + 1) : (int)ratio;
}
static int showdf(char *mntdir, struct obd_statfs *stat,
total = (stat->os_blocks * stat->os_bsize) >> shift;
}
- ratio = obd_statfs_ratio(stat);
+ ratio = obd_statfs_ratio(stat, flags & MNTDF_INODES);
if (flags & MNTDF_COOKED) {
int i;
}
for (tp = types; tp->st_name != NULL; tp++) {
+ bool have_ost = false;
+
if (!(tp->st_op & ops))
continue;
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)
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;
}
}
sd_st;
const struct obd_statfs *st2 = &((const struct ll_statfs_data *)sd2)->
sd_st;
- int r1 = obd_statfs_ratio(st1);
- int r2 = obd_statfs_ratio(st2);
+ int r1 = obd_statfs_ratio(st1, false);
+ int r2 = obd_statfs_ratio(st2, false);
int64_t result = r1 - r2;
/* if both space usage are above 90, compare free inodes */
{ .val = 'D', .name = "default", .has_arg = no_argument },
{ .val = 'D', .name = "default_stripe", .has_arg = no_argument },
{ .val = 'H', .name = "mdt-hash", .has_arg = required_argument },
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 17, 53, 0)
{ .val = 'i', .name = "mdt-index", .has_arg = required_argument },
+ { .val = 'i', .name = "mdt", .has_arg = required_argument },
+#else
+ { .val = 'm', .name = "mdt-index", .has_arg = required_argument },
+ { .val = 'm', .name = "mdt", .has_arg = required_argument },
+#endif
#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
{ .val = 'i', .name = "index", .has_arg = required_argument },
#endif
}
break;
case 'i':
+#if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 17, 53, 0)
+ case 'm':
+#endif
+ fprintf(stderr, "warning: '-m' is deprecated, "
+ "use '--mode' or '-o' instead\n");
#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
if (strcmp(argv[optind - 1], "--index") == 0)
fprintf(stderr,
if (lsa.lsa_stripe_off == LLAPI_LAYOUT_DEFAULT)
lsa.lsa_stripe_off = mdts[0];
break;
-#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 16, 53, 0)
+#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 15, 53, 0)
case 'm':
fprintf(stderr, "warning: '-m' is deprecated, "
"use '--mode' or '-o' instead\n");
/* don't use server whose usage is above 90% */
while (nr != param->lsp_stripe_count &&
- obd_statfs_ratio(&lsb->sb_buf[nr].sd_st)
- > 90)
+ obd_statfs_ratio(&lsb->sb_buf[nr].sd_st,
+ false) > 90)
nr = MAX(param->lsp_stripe_count,
nr / 2);
int c;
int rc = 0;
struct option long_opts[] = {
+ { .val = 'm', .name = "mdt", .has_arg = required_argument },
{ .val = 'm', .name = "mdt-index", .has_arg = required_argument },
{ .val = 'v', .name = "verbose", .has_arg = no_argument },
{ .name = NULL } };
static int lfs_check(int argc, char **argv)
{
- int rc;
- char mntdir[PATH_MAX] = {'\0'};
- int num_types = 1;
- char *obd_types[2];
- char obd_type1[4];
- char obd_type2[4];
+ char mntdir[PATH_MAX] = {'\0'};
+ int num_types = 1;
+ char *obd_types[3];
+ char obd_type1[4];
+ char obd_type2[4];
+ char obd_type3[4];
+ int rc;
if (argc != 2) {
fprintf(stderr, "%s check: server type must be specified\n",
return CMD_HELP;
}
- obd_types[0] = obd_type1;
- obd_types[1] = obd_type2;
-
- if (strcmp(argv[1], "osts") == 0) {
- strcpy(obd_types[0], "osc");
- } else if (strcmp(argv[1], "mds") == 0) {
- strcpy(obd_types[0], "mdc");
- } else if (strcmp(argv[1], "servers") == 0) {
- num_types = 2;
- strcpy(obd_types[0], "osc");
- strcpy(obd_types[1], "mdc");
+ obd_types[0] = obd_type1;
+ obd_types[1] = obd_type2;
+ obd_types[2] = obd_type3;
+
+ if (strcmp(argv[1], "osts") == 0) {
+ strcpy(obd_types[0], "osc");
+ } else if (strcmp(argv[1], "mdts") == 0 ||
+ strcmp(argv[1], "mds") == 0) {
+ strcpy(obd_types[0], "mdc");
+ } else if (strcmp(argv[1], "mgts") == 0) {
+ strcpy(obd_types[0], "mgc");
+ } else if (strcmp(argv[1], "all") == 0 ||
+ strcmp(argv[1], "servers") == 0) {
+ num_types = 3;
+ strcpy(obd_types[0], "osc");
+ strcpy(obd_types[1], "mdc");
+ strcpy(obd_types[2], "mgc");
} else {
fprintf(stderr, "%s check: unrecognized option '%s'\n",
progname, argv[1]);
/* 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);
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 },
case 'o':
outfile = optarg;
break;
+ default:
+ fprintf(stderr, "%s: option '%s' unrecognized.\n",
+ progname, argv[optind - 1]);
+ return -EINVAL;
}
}
/* 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;
/* 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;
}
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;
}
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;
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.
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;
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;
}
return CMD_HELP;
}
- return rc;
+ return 0;
}
/**