From a796b10fa2609af6ab1869a04ea6cc6c2c9051ec Mon Sep 17 00:00:00 2001 From: Frederick Dilger Date: Wed, 24 Jul 2024 15:59:36 -0600 Subject: [PATCH] LU-16446 utils: specify total count for mirror extend The 'lfs mirror extend -N' can now be used to specify the total number of mirrors to create on a file by using '=' infront of the COUNT: 'lfs mirror extend -N=TOTAL_COUNT' or 'lfs mirror extend --mirror-count==TOTAL_COUNT' This is a no-op if the specified number of mirrors already exists on that file. Signed-off-by: Frederick Dilger Change-Id: I76fc416b4dc2c37edf99926bae9a8d42167a49ab Reviewed-on: https://review.whamcloud.com/c/fs/lustre-release/+/55867 Reviewed-by: Alexandre Ioffe Reviewed-by: Andreas Dilger Reviewed-by: Oleg Drokin Tested-by: jenkins Tested-by: Maloo --- lustre/doc/lfs-mirror-extend.1 | 17 +++-- lustre/include/lustre/lustreapi.h | 1 + lustre/tests/sanity-flr.sh | 2 - lustre/utils/lfs.c | 132 ++++++++++++++++++++------------------ lustre/utils/liblustreapi.c | 33 ++++++++++ 5 files changed, 117 insertions(+), 68 deletions(-) diff --git a/lustre/doc/lfs-mirror-extend.1 b/lustre/doc/lfs-mirror-extend.1 index fe1943c..572f5d8 100644 --- a/lustre/doc/lfs-mirror-extend.1 +++ b/lustre/doc/lfs-mirror-extend.1 @@ -19,12 +19,21 @@ The file \fIFILENAME\fR can already be a mirrored file, or just a regular non-mirrored file. If it's a non-mirrored file, then the command will convert it to a mirrored file. .br -The \fB\-\-mirror\-count\fR|\fB\-N\fR option is optional and indicates how many +The +.BR --mirror-count | -N +option is optional and indicates how many mirrors that have the same layout will be added. It can be repeated multiple times to separate mirrors that have different layouts. The \fIMIRROR_COUNT\fR -argument is optional and defaults to 1 if it's not specified; if specified, it -must follow the option without a space. If \fB\-\-mirror\-count\fR|\fB\-N\fR is -not specified, the default value of 1 will be used. +can be specified with a preceding '=' to indicate the number of total mirrors +desired for the layout, such as +\fB\-\-mirror\-count\fR==\fITOTAL_MIRROR_COUNT\fR or +\fB\-N\fR=\fITOTAL_MIRROR_COUNT\fR. This will create mirrors until the total +number of mirrors in the layout match \fITOTAL_MIRROR_COUNT\fR, this also means +that if there are already at least \fITOTAL_MIRROR_COUNT\fR mirrors in the +layout then no new mirrors will be created. The \fIMIRROR_COUNT\fR argument is +optional and defaults to 1 if it's not specified; if specified, it must follow +the option without a space. If \fB\-\-mirror\-count\fR|\fB\-N\fR is not +specified, the default value of 1 will be used. .br The \fISETSTRIPE_OPTIONS\fR specify the specific layout for the mirror. It can be a plain layout with specific striping pattern or a composite layout like diff --git a/lustre/include/lustre/lustreapi.h b/lustre/include/lustre/lustreapi.h index 9791584..2a799d4 100644 --- a/lustre/include/lustre/lustreapi.h +++ b/lustre/include/lustre/lustreapi.h @@ -176,6 +176,7 @@ int llapi_file_get_stripe(const char *path, struct lov_user_md *lum); int llapi_file_lookup(int dirfd, const char *name); void llapi_set_command_name(const char *cmd); void llapi_clear_command_name(void); +int llapi_get_lmm_from_path(const char *path, struct lov_user_md_v1 **lmmbuf); enum llapi_layout_verbose { VERBOSE_STRIPE_COUNT = 0x1, diff --git a/lustre/tests/sanity-flr.sh b/lustre/tests/sanity-flr.sh index e2e22ec..69778e5 100644 --- a/lustre/tests/sanity-flr.sh +++ b/lustre/tests/sanity-flr.sh @@ -312,8 +312,6 @@ test_0a() { # create parent directory mkdir $td || error "mkdir $td failed" - $mirror_cmd $tf &> /dev/null && error "miss -N option" - $mirror_cmd -N $tf || error "create mirrored file $tf failed" verify_mirror_count $tf 1 id=$($LFS getstripe -I $tf) diff --git a/lustre/utils/lfs.c b/lustre/utils/lfs.c index 786062d..bbb4284 100755 --- a/lustre/utils/lfs.c +++ b/lustre/utils/lfs.c @@ -193,24 +193,6 @@ static inline int lfs_mirror_create(int argc, char **argv) static inline int lfs_mirror_extend(int argc, char **argv) { - int i; - - for (i = 0; i < argc; i++) - if (strstr(argv[i], "-N") || - strstr(argv[i], "--mirror-count")) - break; - - /* add -N if not specified */ - if (i == argc) { - char *tmp[argc + 1]; - - tmp[0] = argv[0]; /* extend */ - tmp[1] = "-N"; - memcpy(tmp + 2, argv + 1, (argc - 1) * sizeof(*argv)); - - return lfs_setstripe_internal(argc + 1, tmp, SO_MIRROR_EXTEND); - } - return lfs_setstripe_internal(argc, argv, SO_MIRROR_EXTEND); } @@ -283,11 +265,10 @@ command_t mirror_cmdlist[] = { }, { .pc_name = "extend", .pc_func = lfs_mirror_extend, .pc_help = "Extend a mirrored file.\n" - "Usage: lfs mirror extend " - "--mirror-count|-N[MIRROR_COUNT] [--no-verify]|\n" - "\t\t[--stats|--stats-interval=STATS_INTERVAL]|\n" +"Usage: lfs mirror extend [--mirror-count|-N[MIRROR_COUNT]]\n" + "\t\t[--no-verify] [--stats|--stats-interval=STATS_INTERVAL]\n" "\t\t[--bandwidth-limit|--W BANDWIDTH]\n" - "\t\t[[-f VICTIM_FILE] |\n" + "\t\t[-f VICTIM_FILE]\n" "\t\t" SSM_SETSTRIPE_OPT "]" " FILENAME ...\n" }, { .pc_name = "split", .pc_func = lfs_mirror_split, @@ -3647,7 +3628,7 @@ enum { LFS_STATS_INTERVAL_OPT, LFS_LINKS_OPT, LFS_ATTRS_OPT, - LFS_XATTRS_MATCH_OPT + LFS_XATTRS_MATCH_OPT, }; #ifndef LCME_USER_MIRROR_FLAGS @@ -3659,39 +3640,40 @@ enum { static int lfs_setstripe_internal(int argc, char **argv, enum setstripe_origin opc) { - struct lfs_setstripe_args lsa = { 0 }; - struct llapi_stripe_param *param = NULL; - struct find_param migrate_mdt_param = { + struct lfs_setstripe_args lsa = { 0 }; + struct llapi_stripe_param *param = NULL; + struct find_param migrate_mdt_param = { .fp_max_depth = -1, .fp_mdt_index = -1, }; - char *fname; - int result = 0; - int result2 = 0; - char *end; - int c; - int delete = 0; - unsigned long long size_units = 1; - bool migrate_mode = false; - bool migrate_mdt_mode = false; - bool setstripe_mode = false; - bool migration_block = false; - __u64 migration_flags = 0; - __u32 tgts[LOV_MAX_STRIPE_COUNT] = { 0 }; - int comp_del = 0, comp_set = 0; - int comp_add = 0; - __u32 comp_id = 0; - struct llapi_layout *layout = NULL; - struct llapi_layout **lpp = &layout; - bool mirror_mode = false; - bool has_m_file = false; - __u32 mirror_count = 0; - enum mirror_flags mirror_flags = 0; - struct mirror_args *mirror_list = NULL; - struct mirror_args *new_mirror = NULL; - struct mirror_args *last_mirror = NULL; - __u16 mirror_id = 0; - char cmd[PATH_MAX]; + char *fname; + int result = 0; + int result2 = 0; + char *end; + int c; + int delete = 0; + unsigned long long size_units = 1; + bool migrate_mode = false; + bool migrate_mdt_mode = false; + bool setstripe_mode = false; + bool migration_block = false; + __u64 migration_flags = 0; + __u32 tgts[LOV_MAX_STRIPE_COUNT] = { 0 }; + int comp_del = 0, comp_set = 0; + int comp_add = 0; + __u32 comp_id = 0; + struct llapi_layout *layout = NULL; + struct llapi_layout **lpp = &layout; + bool mirror_mode = false; + bool mirror_total_mode = false; + bool has_m_file = false; + __u32 mirror_count = 0; + enum mirror_flags mirror_flags = 0; + struct mirror_args *mirror_list = NULL; + struct mirror_args *new_mirror = NULL; + struct mirror_args *last_mirror = NULL; + __u16 mirror_id = 0; + char cmd[PATH_MAX]; bool from_yaml = false; bool from_copy = false; char *template = NULL; @@ -4189,12 +4171,18 @@ static int lfs_setstripe_internal(int argc, char **argv, migration_flags |= LLAPI_MIGRATION_NONBLOCK; break; case 'N': +create_mirror: if (opc == SO_SETSTRIPE) { opc = SO_MIRROR_CREATE; mirror_mode = true; } + mirror_total_mode = false; mirror_count = 1; if (optarg) { + if (optarg[0] == '=') { + mirror_total_mode = true; + optarg++; /* skip '=' */ + } errno = 0; mirror_count = strtoul(optarg, &end, 0); if (errno != 0 || *end != '\0' || @@ -4208,6 +4196,32 @@ static int lfs_setstripe_internal(int argc, char **argv, } } + if (mirror_total_mode) { + char *path = argv[argc-1]; + struct lov_comp_md_v1 *comp_v1; + + result = llapi_get_lmm_from_path(path, (struct lov_user_md_v1 **)&comp_v1); + if (result) { + fprintf(stderr, + "error: %s: cannot get layout from %s: %s\n", + progname, path, strerror(-result)); + goto error; + } + + if (comp_v1->lcm_mirror_count >= mirror_count) + mirror_count = 0; + else + mirror_count -= comp_v1->lcm_mirror_count; + + if (!mirror_count) { + fprintf(stderr, + "warning: the file '%s' already has %d mirrors. No new mirrors will be created\n", + path, + comp_v1->lcm_mirror_count); + break; + } + } + new_mirror = lfs_mirror_alloc(); new_mirror->m_count = mirror_count; @@ -4382,15 +4396,9 @@ static int lfs_setstripe_internal(int argc, char **argv, return CMD_HELP; } - if (mirror_mode && mirror_count == 0) { - fprintf(stderr, - "error: %s: --mirror-count|-N option is required\n", - progname); - result = -EINVAL; - goto error; - } - - if (mirror_mode) { + if (mirror_mode && (!mirror_total_mode || mirror_count)) { + if (mirror_count == 0) + goto create_mirror; if (!setstripe_args_specified(&lsa)) last_mirror->m_inherit = true; if (lsa.lsa_comp_end == 0) diff --git a/lustre/utils/liblustreapi.c b/lustre/utils/liblustreapi.c index d0b5eb4..acc252e 100644 --- a/lustre/utils/liblustreapi.c +++ b/lustre/utils/liblustreapi.c @@ -1950,6 +1950,39 @@ retry_getfileinfo: return ret; } +/** + * Get the mirror layout info from a file. + * + * \param path [in] a string containing the file path + * \param lmmbuf [out] pointer to an lov_user_md_v1 buffer + * that will be set with the mirror layout info + * from the file specified by \a path. + * + * \retval 0 success + * \retval -errno on error + */ +int llapi_get_lmm_from_path(const char *path, struct lov_user_md_v1 **lmmbuf) +{ + size_t lmmlen; + int p = -1; + int rc = 0; + + lmmlen = get_mds_md_size(path); + if (lmmlen < 0) + return -EINVAL; + + p = open_parent(path); + + *lmmbuf = calloc(1, lmmlen); + if (*lmmbuf == NULL) + return -errno; + + rc = get_lmd_info_fd(path, p, 0, *lmmbuf, lmmlen, GET_LMD_STRIPE); + if (p != -1) + close(p); + return rc; +} + static int llapi_semantic_traverse(char *path, int size, int parent, semantic_func_t sem_init, semantic_func_t sem_fini, void *data, -- 1.8.3.1