From 107bf3389aed435c7148463817984af1a22200e7 Mon Sep 17 00:00:00 2001 From: Nikitas Angelinas Date: Fri, 30 Oct 2015 12:08:00 +0800 Subject: [PATCH] LU-7131 utils: add "--erase-param" option to tunefs.lustre This patch is to fix the following issues: - A new option "--erase-param" is added to tunefs.lustre, which allows to remove all instances of a specific parameter. - The behavior of option "--param" is improved a little. It will erase all previously stored instances of the parameter, and then store all new values specified in the command line. - For zfs only, the patch introduces a "null value" rule in the form of "=" to mark a property to be removed from dataset by zfs_write_ldd() finally. - To keep the right semantics, if "--erase-params" is specified, all old parameters should be erased before any new changes are done. - test_89 conf-sanity.sh is added to verify these new features. Seagate-bug-id: MRP-153 Signed-off-by: Nikitas Angelinas Signed-off-by: Emoly Liu Change-Id: Ibc8d81227045471b8e5c56c7faf1275ad8bbbf86 Tested-by: Elena Gryaznova Reviewed-by: Artem Blagodarenko Reviewed-by: Alexey Lyashkov Reviewed-by: Vitaly Fertman Reviewed-on: https://review.whamcloud.com/16359 Reviewed-by: Bobi Jam Tested-by: Jenkins Reviewed-by: Fan Yong Reviewed-by: James Simmons Tested-by: Maloo Reviewed-by: Oleg Drokin --- lustre/doc/mkfs.lustre.8 | 2 +- lustre/doc/tunefs.lustre.8 | 62 +++++++++++---- lustre/tests/conf-sanity.sh | 75 ++++++++++++++++++ lustre/utils/mkfs_lustre.c | 134 +++++++++++++++++++++++++++++--- lustre/utils/mount_utils.c | 25 ++++++ lustre/utils/mount_utils.h | 8 ++ lustre/utils/mount_utils_ldiskfs.c | 9 +++ lustre/utils/mount_utils_zfs.c | 152 +++++++++++++++++++++++++++++++------ 8 files changed, 418 insertions(+), 49 deletions(-) diff --git a/lustre/doc/mkfs.lustre.8 b/lustre/doc/mkfs.lustre.8 index 1c90d5b..1569d10 100644 --- a/lustre/doc/mkfs.lustre.8 +++ b/lustre/doc/mkfs.lustre.8 @@ -111,7 +111,7 @@ Set permanent parameter .I key to value .IR value . -This option can be repeated as desired. Typical options might include: +This option can be repeated as desired. Typical options might include: .RS .I \--param sys.timeout=40 .RS diff --git a/lustre/doc/tunefs.lustre.8 b/lustre/doc/tunefs.lustre.8 index 83fea7d..cc84df8 100644 --- a/lustre/doc/tunefs.lustre.8 +++ b/lustre/doc/tunefs.lustre.8 @@ -31,10 +31,14 @@ mounted. Set user comment about this disk, ignored by Lustre. .TP .BI \--dryrun -Only print what would be done; does not affect the disk +Only print what would be done; does not affect the disk. +.TP +.BI \--erase-param " param" +Remove all previously stored instances of the parameter \fIparam\fR. Attempts +to remove a non-existing parameter appear as successful ones. .TP .BI \--erase-params -Remove all previous parameter info +Remove all previously stored parameter info. .TP .BI \--failnode= nid,... Set the NID(s) of a failover partner. This option can be repeated as desired. @@ -45,10 +49,10 @@ Set the NID(s) of all service partner. This option treats all nodes as equal service nodes. Cannot be used with --failnode. .TP .BI \--fsname= filesystem_name -The Lustre filesystem this service will be part of. Default is 'lustre' +The Lustre filesystem this service will be part of. Default is 'lustre'. .TP .BI \--index= index -Force a particular OST or MDT index +Force a particular OST or MDT index. .TP .BI \--mountfsoptions= opts Set the persistent mount options that will be used when Lustre fs. @@ -67,13 +71,41 @@ Use these options for mounting backing fs while tune.lustre is working. Network(s) to restrict this ost/mdt to. This option can be repeated as desired. .TP .BI \--mgs -Add a configuration management service to this target +Add a configuration management service to this target. .TP .BI \--mgsnode= nid,... Set the NID(s) of the MGS node, required for all targets other than the MGS. .TP .BI \--nomgs -Remove a configuration management service to this target +Remove a configuration management service to this target. +.TP +.BI \--param " key=value" +Set permanent parameter +.I key +to value +.IR value . +This option can be repeated as desired. All previously stored instances of +.IR key +are removed, and new instances specified in the command line are added. +Typical options might include: +.RS +.I \--param sys.timeout=40 +.RS +System obd timeout +.RE +.I \--param lov.stripesize=2M +.RS +Default stripe size +.RE +.I \--param lov.stripecount=2 +.RS +Default stripe count +.RE +.I \--param failover.mode=failout +.RS +Return errors instead of waiting for recovery +.RE +.RE .TP .BI \--force-nohostid Ignore unset hostid for ZFS import protection. To set hostid either set @@ -92,13 +124,13 @@ No clients should be started until all targets have restarted. .br Correct order of operations is: .br -* Unmount all clients of this filesystem +* Unmount all clients of this filesystem. .br -* Unmount MDT and all OSTs of this filesystem +* Unmount MDT and all OSTs of this filesystem. .br -* Run \fBtunefs.lustre --writeconf \fR on every server +* Run \fBtunefs.lustre --writeconf \fR on every server. .br -* Mount MDT and OSTs +* Mount MDT and OSTs. .br * Mount clients .TP @@ -107,12 +139,16 @@ Enable space accounting on old 2.x devices. .SH EXAMPLES .TP -.B tunefs.lustre --erase-param --mgsnode= --writeconf /dev/sda +.B tunefs.lustre --erase-params --mgsnode= --writeconf /dev/sda Change the MGS NID address. (This should be done on every target disk, since they should all be contacting the same MGS.) .TP -.B tunefs.lustre --param="failover.node=192.168.0.13@tcp0" /dev/sda -Add a failover NID location for this target +.B tunefs.lustre --param "failover.node=192.168.0.13@tcp0" /dev/sda ++Remove all previous failover NID locations for this target, and add a new ++failover NID location for this target. ++.TP ++.B tunefs.lustre --erase-param failover.node /dev/sda ++Remove all failover NID locations for this target. .TP .B tunefs.lustre --mgs --mdt --fsname=testfs /dev/sda Upgrade an old 1.4.X Lustre MDT to 1.6. The new filesystem name is "testfs". diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index 6ea18f8..59c1c9b 100755 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -6161,6 +6161,81 @@ test_88() { } run_test 88 "check the default mount options can be overridden" +test_89() { # LU-7131 + [[ $(lustre_version_code $SINGLEMDS) -ge $(version_code 2.9.54) ]] || + { skip "Need MDT version at least 2.9.54" && return 0; } + + local key=failover.node + local val1=192.0.2.254@tcp0 # Reserved IPs, see RFC 5735 + local val2=192.0.2.255@tcp0 + local mdsdev=$(mdsdevname 1) + local params + + stopall + + [ $(facet_fstype mds1) == zfs ] && import_zpool mds1 + # Check that parameters are added correctly + echo "tunefs --param $key=$val1" + do_facet mds "$TUNEFS --param $key=$val1 $mdsdev >/dev/null" || + error "tunefs --param $key=$val1 failed" + params=$(do_facet mds $TUNEFS --dryrun $mdsdev) || + error "tunefs --dryrun failed" + params=${params##*Parameters:} + params=${params%%exiting*} + [ $(echo $params | tr ' ' '\n' | grep -c $key=$val1) = "1" ] || + error "on-disk parameter not added correctly via tunefs" + + # Check that parameters replace existing instances when added + echo "tunefs --param $key=$val2" + do_facet mds "$TUNEFS --param $key=$val2 $mdsdev >/dev/null" || + error "tunefs --param $key=$val2 failed" + params=$(do_facet mds $TUNEFS --dryrun $mdsdev) || + error "tunefs --dryrun failed" + params=${params##*Parameters:} + params=${params%%exiting*} + [ $(echo $params | tr ' ' '\n' | grep -c $key=) = "1" ] || + error "on-disk parameter not replaced via tunefs" + [ $(echo $params | tr ' ' '\n' | grep -c $key=$val2) = "1" ] || + error "on-disk parameter not replaced correctly via tunefs" + + # Check that a parameter is erased properly + echo "tunefs --erase-param $key" + do_facet mds "$TUNEFS --erase-param $key $mdsdev >/dev/null" || + error "tunefs --erase-param $key failed" + params=$(do_facet mds $TUNEFS --dryrun $mdsdev) || + error "tunefs --dryrun failed" + params=${params##*Parameters:} + params=${params%%exiting*} + [ $(echo $params | tr ' ' '\n' | grep -c $key=) = "0" ] || + error "on-disk parameter not erased correctly via tunefs" + + # Check that all the parameters are erased + echo "tunefs --erase-params" + do_facet mds "$TUNEFS --erase-params $mdsdev >/dev/null" || + error "tunefs --erase-params failed" + params=$(do_facet mds $TUNEFS --dryrun $mdsdev) || + error "tunefs --dryrun failed" + params=${params##*Parameters:} + params=${params%%exiting*} + [ -z $params ] || + error "all on-disk parameters not erased correctly via tunefs" + + # Check the order of options --erase-params and --param + echo "tunefs --param $key=$val1 --erase-params" + do_facet mds \ + "$TUNEFS --param $key=$val1 --erase-params $mdsdev >/dev/null"|| + error "tunefs --param $key=$val1 --erase-params failed" + params=$(do_facet mds $TUNEFS --dryrun $mdsdev) || + error "tunefs --dryrun failed" + params=${params##*Parameters:} + params=${params%%exiting*} + [ $(echo $params | tr ' ' '\n') == "$key=$val1" ] || + error "on-disk param not added correctly with --erase-params" + + reformat +} +run_test 89 "check tunefs --param and --erase-param{s} options" + # $1 test directory # $2 (optional) value of max_mod_rpcs_in_flight to set check_max_mod_rpcs_in_flight() { diff --git a/lustre/utils/mkfs_lustre.c b/lustre/utils/mkfs_lustre.c index ab813fa..098e607 100644 --- a/lustre/utils/mkfs_lustre.c +++ b/lustre/utils/mkfs_lustre.c @@ -154,6 +154,7 @@ void usage(FILE *out) "\t\t--replace: replace an old target with the same index\n" "\t\t--stripe-count-hint=#N: for optimizing MDT inode size\n" #else + "\t\t--erase-param : erase all instances of a parameter\n" "\t\t--erase-params: erase all old parameter settings\n" "\t\t--writeconf: erase all config logs for this fs.\n" "\t\t--quota: enable space accounting on old 2.x device.\n" @@ -173,8 +174,10 @@ void usage(FILE *out) /* ==================== Lustre config functions =============*/ -void print_ldd(char *str, struct lustre_disk_data *ldd) +void print_ldd(char *str, struct mkfs_opts *mop) { + struct lustre_disk_data *ldd = &mop->mo_ldd; + printf("\n %s:\n", str); printf("Target: %s\n", ldd->ldd_svname); if (ldd->ldd_svindex == INDEX_UNASSIGNED) @@ -197,7 +200,7 @@ void print_ldd(char *str, struct lustre_disk_data *ldd) ldd->ldd_flags & LDD_F_NO_PRIMNODE? "no_primnode ":"", ldd->ldd_flags & LDD_F_UPGRADE14 ? "upgrade1.4 ":""); printf("Persistent mount opts: %s\n", ldd->ldd_mount_opts); - printf("Parameters:%s\n", ldd->ldd_params); + osd_print_ldd_params(mop); if (ldd->ldd_userdata[0]) printf("Comment: %s\n", ldd->ldd_userdata); printf("\n"); @@ -226,6 +229,71 @@ static inline void badopt(const char *opt, char *type) usage(stderr); } +#ifdef TUNEFS +/** + * Removes all existing instances of the parameter passed in \a param, + * which are in the form of "key=", from the buffer at \a buf. + * + * The parameter can be either in the form of "key" when passed by option + * "--erase-param", or in the form of "key=" when passed by option + * "--param". + * + * \param buf the buffer holding on-disk server parameters. + * \param param the parameter whose instances are to be removed from \a buf. + * \param withval true means the parameter is in the form of "key=" + * false means the parameter is in the form of "key" + * + * \retval 0 success, parameter was erased, + * \retval 1 success, parameter was not found, don't need to do erase_ldd, + * \retval EINVAL failure, invalid input parameter. + */ +static int erase_param(const char *const buf, const char *const param, + bool withval) +{ + char search[PARAM_MAX + 1] = ""; + char *buffer = (char *)buf; + bool found = false; + + if (strlen(param) > PARAM_MAX) { + fprintf(stderr, "%s: param to erase is too long-\n%s\n", + progname, param); + return EINVAL; + } + + /* add_param() writes a space as the first character in ldd_params */ + search[0] = ' '; + + /* "key" or "key=" */ + if (withval) { + char *keyend; + + keyend = strchr(param, '='); + if (!keyend) + return EINVAL; + strncpy(&search[1], param, keyend - param + 1); + } else { + strncpy(&search[1], param, strlen(param)); + strncat(search, "=", 1); + } + + while (1) { + char *space; + + buffer = strstr(buffer, search); + if (!buffer) + return found == true ? 0 : 1; + found = true; + space = strchr(buffer + 1, ' '); + if (space) { + memmove(buffer, space, strlen(space) + 1); + } else { + *buffer = '\0'; + return 0; + } + } +} +#endif + /* from mount_lustre */ /* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */ #define MAXNIDSTR 1024 @@ -308,6 +376,7 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, { "reformat", no_argument, NULL, 'r' }, { "replace", no_argument, NULL, 'R' }, #else + { "erase-param", required_argument, NULL, 'E' }, { "erase-params", no_argument, NULL, 'e' }, { "quota", no_argument, NULL, 'Q' }, { "rename", optional_argument, NULL, 'R' }, @@ -319,7 +388,7 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, #ifndef TUNEFS "b:c:d:k:MOrR"; #else - "eQR::w"; + "E:eQR::w"; #endif struct lustre_disk_data *ldd = &mop->mo_ldd; char new_fsname[16] = { 0 }; @@ -329,6 +398,26 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, int replace = 0; bool index_option = false; +#ifdef TUNEFS + /* For the right semantics, if '-e'/'--erase-params' is specified, + * it must be picked out and all old parameters should be erased + * before any other changes are done. */ + while ((opt = getopt_long(argc, argv, optstring, long_opt, &longidx)) != + EOF) { + switch (opt) { + case 'e': + ldd->ldd_params[0] = '\0'; + mop->mo_flags |= MO_ERASE_ALL; + ldd->ldd_flags |= LDD_F_UPDATE; + break; + default: + break; + } + if (mop->mo_flags & MO_ERASE_ALL) + break; + } + optind = 0; +#endif while ((opt = getopt_long(argc, argv, optstring, long_opt, &longidx)) != EOF) { switch (opt) { @@ -446,10 +535,17 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, *mountopts = optarg; break; case 'p': +#ifdef TUNEFS + /* Removes all existing instances of the parameter + * before adding new values. + */ + rc = erase_param(ldd->ldd_params, optarg, true); + if (rc > 1) + return rc; +#endif rc = add_param(ldd->ldd_params, NULL, optarg); if (rc != 0) return rc; - /* Must update the mgs logs */ ldd->ldd_flags |= LDD_F_UPDATE; break; @@ -539,12 +635,24 @@ int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop, case 'R': replace = 1; break; -#else /* !TUNEFS */ - case 'e': - ldd->ldd_params[0] = '\0'; +#else /* TUNEFS */ + case 'E': + rc = erase_param(ldd->ldd_params, optarg, false); + /* (rc == 1) means not found, so don't need to + * call osd_erase_ldd(). */ + if (rc > 1) + return rc; + if (!rc) { + rc = osd_erase_ldd(mop, optarg); + if (rc) + return rc; + } /* Must update the mgs logs */ ldd->ldd_flags |= LDD_F_UPDATE; break; + case 'e': + /* Already done in the beginning */ + break; case 'Q': mop->mo_flags |= MO_QUOTA; break; @@ -730,7 +838,7 @@ int main(int argc, char *const argv[]) mop.mo_mgs_failnodes++; if (verbose > 0) - print_ldd("Read previous values", ldd); + print_ldd("Read previous values", &mop); #endif /* TUNEFS */ ret = parse_opts(argc, argv, &mop, &mountopts, old_fsname); @@ -782,7 +890,14 @@ int main(int argc, char *const argv[]) ldd->ldd_flags &= ~LDD_F_NEED_INDEX; ldd->ldd_svindex = 0; } +#ifndef TUNEFS if (!IS_MGS(ldd) && (mop.mo_mgs_failnodes == 0)) { +#else + /* Don't check --mgs or --mgsnode if print_only is set or + * --erase-params is set. */ + if (!IS_MGS(ldd) && (mop.mo_mgs_failnodes == 0) && !print_only && + !(mop.mo_flags & MO_ERASE_ALL)) { +#endif fatal(); if (IS_MDT(ldd)) fprintf(stderr, "Must specify --mgs or --mgsnode\n"); @@ -843,7 +958,7 @@ int main(int argc, char *const argv[]) } if (verbose >= 0) - print_ldd("Permanent disk data", ldd); + print_ldd("Permanent disk data", &mop); if (print_only) { printf("exiting before disk write.\n"); @@ -928,7 +1043,6 @@ int main(int argc, char *const argv[]) fprintf(stderr, "failed to write local files\n"); goto out; } - out: osd_fini(); ret2 = loop_cleanup(&mop); diff --git a/lustre/utils/mount_utils.c b/lustre/utils/mount_utils.c index db05359..7c7539c 100644 --- a/lustre/utils/mount_utils.c +++ b/lustre/utils/mount_utils.c @@ -586,6 +586,8 @@ struct module_backfs_ops *load_backfs_module(enum ldd_mount_type mount_type) DLSYM(name, ops, fini); DLSYM(name, ops, read_ldd); DLSYM(name, ops, write_ldd); + DLSYM(name, ops, erase_ldd); + DLSYM(name, ops, print_ldd_params); DLSYM(name, ops, is_lustre); DLSYM(name, ops, make_lustre); DLSYM(name, ops, prepare_lustre); @@ -666,6 +668,29 @@ int osd_read_ldd(char *dev, struct lustre_disk_data *ldd) return ret; } +/* Erase param from the server config files */ +int osd_erase_ldd(struct mkfs_opts *mop, char *param) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + int ret; + + if (backfs_mount_type_okay(ldd->ldd_mount_type)) + ret = backfs_ops[ldd->ldd_mount_type]->erase_ldd(mop, param); + else + ret = EINVAL; + + return ret; +} + +/* Print ldd_params */ +void osd_print_ldd_params(struct mkfs_opts *mop) +{ + struct lustre_disk_data *ldd = &mop->mo_ldd; + + if (backfs_mount_type_okay(ldd->ldd_mount_type)) + backfs_ops[ldd->ldd_mount_type]->print_ldd_params(mop); +} + /* Was this device formatted for Lustre */ int osd_is_lustre(char *dev, unsigned *mount_type) { diff --git a/lustre/utils/mount_utils.h b/lustre/utils/mount_utils.h index 2b1ac8f..c0c4526 100644 --- a/lustre/utils/mount_utils.h +++ b/lustre/utils/mount_utils.h @@ -73,10 +73,14 @@ extern int failover; #define MO_QUOTA 0x10 #define MO_NOHOSTID_CHECK 0x20 #define MO_RENAME 0x40 +#define MO_ERASE_ALL 0x80 #define MAX_LOOP_DEVICES 16 #define INDEX_UNASSIGNED 0xFFFF +/* Maximum length of on-disk parameters in the form key= */ +#define PARAM_MAX 4096 + /* used to describe the options to format the lustre disk, not persistent */ struct mkfs_opts { struct lustre_disk_data mo_ldd; /* to be written in MOUNT_DATA_FILE */ @@ -154,6 +158,8 @@ int loop_cleanup(struct mkfs_opts *mop); /* generic target support */ int osd_write_ldd(struct mkfs_opts *mop); int osd_read_ldd(char *dev, struct lustre_disk_data *ldd); +int osd_erase_ldd(struct mkfs_opts *mop, char *param); +void osd_print_ldd_params(struct mkfs_opts *mop); int osd_is_lustre(char *dev, unsigned *mount_type); int osd_make_lustre(struct mkfs_opts *mop); int osd_prepare_lustre(struct mkfs_opts *mop, @@ -171,6 +177,8 @@ struct module_backfs_ops { void (*fini)(void); int (*read_ldd)(char *ds, struct lustre_disk_data *ldd); int (*write_ldd)(struct mkfs_opts *mop); + int (*erase_ldd)(struct mkfs_opts *mop, char *param); + void (*print_ldd_params)(struct mkfs_opts *mop); int (*is_lustre)(char *dev, enum ldd_mount_type *mount_type); int (*make_lustre)(struct mkfs_opts *mop); int (*prepare_lustre)(struct mkfs_opts *mop, diff --git a/lustre/utils/mount_utils_ldiskfs.c b/lustre/utils/mount_utils_ldiskfs.c index b1edf54..2c41df3 100644 --- a/lustre/utils/mount_utils_ldiskfs.c +++ b/lustre/utils/mount_utils_ldiskfs.c @@ -389,6 +389,15 @@ int ldiskfs_read_ldd(char *dev, struct lustre_disk_data *mo_ldd) return ret; } +int ldiskfs_erase_ldd(struct mkfs_opts *mop, char *param) +{ + return 0; +} + +void ldiskfs_print_ldd_params(struct mkfs_opts *mop) +{ + printf("Parameters:%s\n", mop->mo_ldd.ldd_params); +} /* Display the need for the latest e2fsprogs to be installed. make_backfs * indicates if the caller is make_lustre_backfs() or not. */ diff --git a/lustre/utils/mount_utils_zfs.c b/lustre/utils/mount_utils_zfs.c index 72dbb69..6b33101 100644 --- a/lustre/utils/mount_utils_zfs.c +++ b/lustre/utils/mount_utils_zfs.c @@ -136,15 +136,67 @@ static int zfs_set_prop_str(zfs_handle_t *zhp, char *prop, void *val) } /* + * Remove a property from zfs property dataset + */ +static int zfs_remove_prop(zfs_handle_t *zhp, nvlist_t *nvl, char *propname) +{ + nvlist_remove_all(nvl, propname); + /* XXX: please replace zfs_prop_inherit() if there is a better function + * to call zfs_ioctl() to update data on-disk. + */ + return zfs_prop_inherit(zhp, propname, false); +} + +static int zfs_erase_prop(zfs_handle_t *zhp, char *param) +{ + nvlist_t *nvl; + char propname[ZFS_MAXPROPLEN]; + int len = strlen(param) + strlen(LDD_PREFIX); + + if (len > ZFS_MAXPROPLEN) { + fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n", + progname, param); + return EINVAL; + } + + nvl = zfs_get_user_props(zhp); + if (!nvl) + return ENOENT; + + snprintf(propname, len + 1, "%s%s", LDD_PREFIX, param); + return zfs_remove_prop(zhp, nvl, propname); +} + +static int zfs_erase_allprops(zfs_handle_t *zhp) +{ + nvlist_t *nvl; + nvpair_t *curr = NULL; + + nvl = zfs_get_user_props(zhp); + if (!nvl) + return ENOENT; + + curr = nvlist_next_nvpair(nvl, curr); + while (curr) { + nvpair_t *next = nvlist_next_nvpair(nvl, curr); + + zfs_remove_prop(zhp, nvl, nvpair_name(curr)); + curr = next; + } + + return 0; +} + +/* * Map '= ...' pairs in the passed string to dataset properties - * of the form 'lustre:='. Malformed = pairs will - * be skipped. + * of the form 'lustre:='. "=" means to remove this key + * from the dataset. */ static int zfs_set_prop_params(zfs_handle_t *zhp, char *params) { char *params_dup, *token, *key, *value; char *save_token = NULL; - char prop_name[ZFS_MAXPROPLEN]; + char propname[ZFS_MAXPROPLEN]; int ret = 0; params_dup = strdup(params); @@ -158,15 +210,20 @@ static int zfs_set_prop_params(zfs_handle_t *zhp, char *params) continue; value = strtok(NULL, "="); - if (value == NULL) - continue; - - sprintf(prop_name, "%s%s", LDD_PREFIX, key); - vprint(" %s=%s\n", prop_name, value); + if (!value) { + /* remove this prop when its value is null */ + ret = zfs_erase_prop(zhp, key); + if (ret) + break; + } else { + snprintf(propname, strlen(LDD_PREFIX) + strlen(key) + 1, + "%s%s", LDD_PREFIX, key); + vprint(" %s=%s\n", propname, value); - ret = zfs_prop_set(zhp, prop_name, value); - if (ret) - break; + ret = zfs_prop_set(zhp, propname, value); + if (ret) + break; + } token = strtok_r(NULL, " ", &save_token); } @@ -263,10 +320,14 @@ int zfs_write_ldd(struct mkfs_opts *mop) ret = zfs_check_hostid(mop); if (ret != 0) - goto out; + goto out_close; vprint("Writing %s properties\n", ds); + if (mop->mo_flags & MO_ERASE_ALL) + ret = zfs_erase_allprops(zhp); + ret = zfs_set_prop_params(zhp, ldd->ldd_params); + for (i = 0; special_ldd_prop_params[i].zlpb_prop_name != NULL; i++) { bridge = &special_ldd_prop_params[i]; ret = bridge->zlpb_set_prop_fn(zhp, bridge->zlpb_prop_name, @@ -275,14 +336,26 @@ int zfs_write_ldd(struct mkfs_opts *mop) goto out_close; } - ret = zfs_set_prop_params(zhp, ldd->ldd_params); - out_close: zfs_close(zhp); out: return ret; } +/* Mark a property to be removed by the form of "key=" */ +int zfs_erase_ldd(struct mkfs_opts *mop, char *param) +{ + char key[ZFS_MAXPROPLEN] = ""; + + if (strlen(LDD_PREFIX) + strlen(param) > ZFS_MAXPROPLEN) { + fprintf(stderr, "%s: zfs prop to erase is too long-\n%s\n", + progname, param); + return EINVAL; + } + snprintf(key, strlen(param) + 2, "%s=", param); + return add_param(mop->mo_ldd.ldd_params, key, ""); +} + static int zfs_get_prop_int(zfs_handle_t *zhp, char *prop, void *val) { nvlist_t *propval; @@ -335,22 +408,18 @@ static int zfs_is_special_ldd_prop_param(char *name) return 0; } -static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len) +static int zfs_get_prop_params(zfs_handle_t *zhp, char *param) { nvlist_t *props; nvpair_t *nvp; - char key[ZFS_MAXPROPLEN]; - char *value; + char key[ZFS_MAXPROPLEN] = ""; + char value[PARAM_MAX] = ""; int ret = 0; props = zfs_get_user_props(zhp); if (props == NULL) return ENOENT; - value = malloc(len); - if (value == NULL) - return ENOMEM; - nvp = NULL; while (nvp = nvlist_next_nvpair(props, nvp), nvp) { ret = zfs_get_prop_str(zhp, nvpair_name(nvp), value); @@ -364,14 +433,11 @@ static int zfs_get_prop_params(zfs_handle_t *zhp, char *param, int len) continue; sprintf(key, "%s=", nvpair_name(nvp) + strlen(LDD_PREFIX)); - ret = add_param(param, key, value); if (ret) break; } - free(value); - return ret; } @@ -403,7 +469,7 @@ int zfs_read_ldd(char *ds, struct lustre_disk_data *ldd) goto out_close; } - ret = zfs_get_prop_params(zhp, ldd->ldd_params, 4096); + ret = zfs_get_prop_params(zhp, ldd->ldd_params); if (ret && (ret != ENOENT)) goto out_close; @@ -415,6 +481,42 @@ out: return ret; } +/* Print ldd params */ +void zfs_print_ldd_params(struct mkfs_opts *mop) +{ + char *from = mop->mo_ldd.ldd_params; + char *to; + int len; + + vprint("Parameters:"); + while (from) { + /* skip those keys to be removed in the form of "key=" */ + to = strstr(from, "= "); + if (!to) + /* "key=" may be in the end */ + if (*(from + strlen(from) - 1) == '=') + to = from + strlen(from) - 1; + + /* find " " inward */ + len = strlen(from); + if (to) { + len = strlen(from) - strlen(to); + while ((*(from + len) != ' ') && len) + len--; + } + if (len) + /* no space in the end */ + vprint("%*.*s", len, len, from); + + /* If there is no "key=" or "key=" is in the end, stop. */ + if (!to || strlen(to) == 1) + break; + + /* skip "=" */ + from = to + 1; + } +} + int zfs_is_lustre(char *ds, unsigned *mount_type) { struct lustre_disk_data tmp_ldd; -- 1.8.3.1