From patchwork Fri Jul 21 05:07:32 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guan Junxiong X-Patchwork-Id: 9856157 X-Patchwork-Delegate: snitzer@redhat.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id BE5E460392 for ; Fri, 21 Jul 2017 05:16:26 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B21CB286DF for ; Fri, 21 Jul 2017 05:16:26 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A6B8628733; Fri, 21 Jul 2017 05:16:26 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id C4E97286DF for ; Fri, 21 Jul 2017 05:16:25 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A076CC073D65; Fri, 21 Jul 2017 05:16:24 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com A076CC073D65 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=huawei.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=dm-devel-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com A076CC073D65 Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 77ED76047E; Fri, 21 Jul 2017 05:16:24 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 1AC144A467; Fri, 21 Jul 2017 05:16:24 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v6L5Errp007223 for ; Fri, 21 Jul 2017 01:14:53 -0400 Received: by smtp.corp.redhat.com (Postfix) id 3678D60462; Fri, 21 Jul 2017 05:14:53 +0000 (UTC) Delivered-To: dm-devel@redhat.com Received: from mx1.redhat.com (ext-mx01.extmail.prod.ext.phx2.redhat.com [10.5.110.25]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 305666047C for ; Fri, 21 Jul 2017 05:14:51 +0000 (UTC) Received: from szxga01-in.huawei.com (szxga01-in.huawei.com [45.249.212.187]) (using TLSv1 with cipher RC4-SHA (112/128 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 6E87B81F01 for ; Fri, 21 Jul 2017 05:14:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 6E87B81F01 Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=huawei.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=guanjunxiong@huawei.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 6E87B81F01 Received: from 172.30.72.57 (EHLO DGGEML403-HUB.china.huawei.com) ([172.30.72.57]) by dggrg01-dlp.huawei.com (MOS 4.4.6-GA FastPath queued) with ESMTP id ASP12681; Fri, 21 Jul 2017 13:07:54 +0800 (CST) Received: from huawei.com (10.169.94.217) by DGGEML403-HUB.china.huawei.com (10.3.17.33) with Microsoft SMTP Server id 14.3.301.0; Fri, 21 Jul 2017 13:07:44 +0800 From: Guan Junxiong To: , , , , , Date: Fri, 21 Jul 2017 13:07:32 +0800 Message-ID: <1500613652-9084-4-git-send-email-guanjunxiong@huawei.com> In-Reply-To: <1500613652-9084-1-git-send-email-guanjunxiong@huawei.com> References: <1500613652-9084-1-git-send-email-guanjunxiong@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.169.94.217] X-CFilter-Loop: Reflected X-Mirapoint-Virus-RAPID-Raw: score=unknown(0), refid=str=0001.0A020201.59718C2A.0077, ss=1, re=0.000, recu=0.000, reip=0.000, cl=1, cld=1, fgs=0, ip=0.0.0.0, so=2014-11-16 11:51:01, dmn=2013-03-21 17:37:32 X-Mirapoint-Loop-Id: 2982831289bda0b441cba0ceee946a7f X-Greylist: Delayed for 00:06:53 by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Fri, 21 Jul 2017 05:14:50 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Fri, 21 Jul 2017 05:14:50 +0000 (UTC) for IP:'45.249.212.187' DOMAIN:'szxga01-in.huawei.com' HELO:'szxga01-in.huawei.com' FROM:'guanjunxiong@huawei.com' RCPT:'' X-RedHat-Spam-Score: -0.102 (DCC_REPUT_13_19, RP_MATCHES_RCVD, SPF_PASS) 45.249.212.187 szxga01-in.huawei.com 45.249.212.187 szxga01-in.huawei.com X-Scanned-By: MIMEDefang 2.78 on 10.5.110.25 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-loop: dm-devel@redhat.com Cc: zouming.zouming@huawei.com, chengjike.cheng@huawei.com, guanjunxiong@huawei.com, philip.yang@huawei.com, shenhong09@huawei.com, hege09@huawei.com Subject: [dm-devel] [PATCH RFC 3/3] multipath-tools: coalesce heterogenous paths by referencing method X-BeenThere: dm-devel@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: device-mapper development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: dm-devel-bounces@redhat.com Errors-To: dm-devel-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Fri, 21 Jul 2017 05:16:25 +0000 (UTC) X-Virus-Scanned: ClamAV using ClamSMTP This patch supports migrating data for heterogenous arrays without interrupting uplayer transaction. The usage is as follows: The new attribute named uid_reference provides a unique path identifier for some paths by referencing another path's identifier. Therefor those paths can be coalesced. This is useful to migrate data for heterogenous arrays without interrupting uplayer transaction. If you are going to let sda, sdb and sdc use the unique path identifier of the sdd, you can add the uid_reference field as follows into the vendor specific _devices_ section, _override_ section or the _default_ section in the multipath.conf file. uid_reference "sd[a-c] sdd" where the first parameter which can be regular expression specifies the target devices to be assigned with the wwid of the source device. The second parameter is the source device to be referenced by the target devices. The source device only supports one device. Here is another expamle I use: uid_reference "nvme[1-9]*n[0-9]* nvme0n1" The implementation outline is as follows: 1. To let multipath configuation suppport the new attribute uid_reference in the, we add a new attribute named uid_reference which can be added in the _default_, _override_, and _devices_ section. 2. When the target path is going to get unique id, we fetch the source path's unique id at first. To simplify logic and code, we use recurring method where the recurring ending condition is speficied by the flags in the path. 3. Copy the source path wwid to the target path's. Signed-off-by: Junxiong Guan --- libmultipath/config.c | 13 +++++ libmultipath/config.h | 3 ++ libmultipath/dict.c | 11 ++++ libmultipath/discovery.c | 123 ++++++++++++++++++++++++++++++++++++++++++++- libmultipath/propsel.c | 25 +++++++++ libmultipath/structs.h | 1 + libmultipath/structs_vec.c | 1 + multipath/multipath.conf.5 | 37 +++++++++++++- 8 files changed, 211 insertions(+), 3 deletions(-) diff --git a/libmultipath/config.c b/libmultipath/config.c index 6b236019..fa42dcd9 100644 --- a/libmultipath/config.c +++ b/libmultipath/config.c @@ -176,6 +176,9 @@ free_hwe (struct hwentry * hwe) if (hwe->uid_attribute) FREE(hwe->uid_attribute); + if (hwe->uid_reference) + FREE(hwe->uid_reference); + if (hwe->features) FREE(hwe->features); @@ -236,6 +239,9 @@ free_mpe (struct mpentry * mpe) if (mpe->uid_attribute) FREE(mpe->uid_attribute); + if (mpe->uid_reference) + FREE(mpe->uid_reference); + if (mpe->alias) FREE(mpe->alias); @@ -323,6 +329,7 @@ merge_hwe (struct hwentry * dst, struct hwentry * src) merge_str(revision); merge_str(getuid); merge_str(uid_attribute); + merge_str(uid_reference); merge_str(features); merge_str(hwhandler); merge_str(selector); @@ -388,6 +395,9 @@ store_hwe (vector hwtable, struct hwentry * dhwe) if (dhwe->uid_attribute && !(hwe->uid_attribute = set_param_str(dhwe->uid_attribute))) goto out; + if (dhwe->uid_reference && !(hwe->uid_reference = set_param_str(dhwe->uid_reference))) + goto out; + if (dhwe->getuid && !(hwe->getuid = set_param_str(dhwe->getuid))) goto out; @@ -500,6 +510,9 @@ free_config (struct config * conf) if (conf->uid_attribute) FREE(conf->uid_attribute); + if (conf->uid_reference) + FREE(conf->uid_reference); + if (conf->uid_attrs) FREE(conf->uid_attrs); diff --git a/libmultipath/config.h b/libmultipath/config.h index ffc69b5f..709e9f19 100644 --- a/libmultipath/config.h +++ b/libmultipath/config.h @@ -47,6 +47,7 @@ struct hwentry { char * product; char * revision; char * uid_attribute; + char * uid_reference; char * getuid; char * features; char * hwhandler; @@ -84,6 +85,7 @@ struct mpentry { char * wwid; char * alias; char * uid_attribute; + char * uid_reference; char * getuid; char * selector; char * features; @@ -172,6 +174,7 @@ struct config { char * selector; char * uid_attrs; char * uid_attribute; + char * uid_reference; char * getuid; char * features; char * hwhandler; diff --git a/libmultipath/dict.c b/libmultipath/dict.c index 82066f67..7a5514ad 100644 --- a/libmultipath/dict.c +++ b/libmultipath/dict.c @@ -258,6 +258,14 @@ declare_ovr_snprint(uid_attribute, print_str) declare_hw_handler(uid_attribute, set_str) declare_hw_snprint(uid_attribute, print_str) +declare_def_handler(uid_reference, set_str) +declare_def_snprint(uid_reference, print_str) +declare_ovr_handler(uid_reference, set_str) +declare_ovr_snprint(uid_reference, print_str) +declare_hw_handler(uid_reference, set_str) +declare_hw_snprint(uid_reference, print_str) + + declare_def_handler(getuid, set_str) declare_def_snprint(getuid, print_str) declare_ovr_handler(getuid, set_str) @@ -1400,6 +1408,7 @@ init_keywords(vector keywords) install_keyword("path_grouping_policy", &def_pgpolicy_handler, &snprint_def_pgpolicy); install_keyword("uid_attrs", &def_uid_attrs_handler, &snprint_def_uid_attrs); install_keyword("uid_attribute", &def_uid_attribute_handler, &snprint_def_uid_attribute); + install_keyword("uid_reference", &def_uid_reference_handler, &snprint_def_uid_reference); install_keyword("getuid_callout", &def_getuid_handler, &snprint_def_getuid); install_keyword("prio", &def_prio_name_handler, &snprint_def_prio_name); install_keyword("prio_args", &def_prio_args_handler, &snprint_def_prio_args); @@ -1499,6 +1508,7 @@ init_keywords(vector keywords) install_keyword("product_blacklist", &hw_bl_product_handler, &snprint_hw_bl_product); install_keyword("path_grouping_policy", &hw_pgpolicy_handler, &snprint_hw_pgpolicy); install_keyword("uid_attribute", &hw_uid_attribute_handler, &snprint_hw_uid_attribute); + install_keyword("uid_reference", &hw_uid_reference_handler, &snprint_hw_uid_reference); install_keyword("getuid_callout", &hw_getuid_handler, &snprint_hw_getuid); install_keyword("path_selector", &hw_selector_handler, &snprint_hw_selector); install_keyword("path_checker", &hw_checker_name_handler, &snprint_hw_checker_name); @@ -1534,6 +1544,7 @@ init_keywords(vector keywords) install_keyword_root("overrides", &overrides_handler); install_keyword("path_grouping_policy", &ovr_pgpolicy_handler, &snprint_ovr_pgpolicy); install_keyword("uid_attribute", &ovr_uid_attribute_handler, &snprint_ovr_uid_attribute); + install_keyword("uid_reference", &ovr_uid_reference_handler, &snprint_ovr_uid_reference); install_keyword("getuid_callout", &ovr_getuid_handler, &snprint_ovr_getuid); install_keyword("path_selector", &ovr_selector_handler, &snprint_ovr_selector); install_keyword("path_checker", &ovr_checker_name_handler, &snprint_ovr_checker_name); diff --git a/libmultipath/discovery.c b/libmultipath/discovery.c index 1d3f591e..ce2343cd 100644 --- a/libmultipath/discovery.c +++ b/libmultipath/discovery.c @@ -1768,6 +1768,118 @@ get_vpd_uid(struct path * pp) return get_vpd_sysfs(parent, 0x83, pp->wwid, WWID_SIZE); } +static int +check_uid_reference(struct path * pp, char *uid_reference) +{ + const char *msg_id = "uid_reference"; + const char *from_dev; + const char *to_dev_regex; + char *args, *temp; + char split_char[] = " \t"; + regex_t path_regex; + int ret = -EINVAL; + + if (!uid_reference) + return -EINVAL; + + args = temp = STRDUP(uid_reference); + if (!args) + return -ENOMEM; + + to_dev_regex = get_next_string(&temp, split_char); + if (!to_dev_regex) { + condlog(3, "%s: no target devices provided for %s", + pp->dev, msg_id); + goto out1; + } + + if (!temp || !(from_dev = get_next_string(&temp, split_char))) { + condlog(3, "%s: no source device provided for %s", + pp->dev, msg_id); + goto out1; + } + + if (regcomp(&path_regex, to_dev_regex, REG_EXTENDED|REG_NOSUB)) + goto out2; + + /* + * to discard if the target device is in the source device list + */ + if (!regexec(&path_regex, from_dev, 0, NULL, 0)) { + condlog(3, "%s: invalid parameter for %s because the source \ + devices include the target device", pp->dev, msg_id); + goto out2; + } + + if (regexec(&path_regex, pp->dev, 0, NULL, 0)) { + goto out2; + } + + ret = 0; +out2: + regfree(&path_regex); +out1: + FREE(args); + + return ret; +} + +static int +get_uid_reference(struct path * pp, char *uid_reference) +{ + const char *msg_id = "uid_reference"; + int ret; + ssize_t len = -1; + + const char *from_dev = NULL; + char *args, *temp; + char split_char[] = " \t"; + struct path *from_pp = NULL; + struct udev_device *from_udev; + struct config *conf; + + args = temp = STRDUP(uid_reference); + if (!args) + return -ENOMEM; + + /* + * the uid_reference has been checked by check_uid_reference, + * so discard handle the exceptions + */ + get_next_string(&temp, split_char); + from_dev = get_next_string(&temp, split_char); + + from_udev = udev_device_new_from_subsystem_sysname(udev, "block", + from_dev); + if (!from_udev) { + condlog(3, "%s: (%s) failed to get udev_device for (%s)", + pp->dev, msg_id, from_dev); + goto out1; + } + + conf = get_multipath_config(); + ret = alloc_path_with_pathinfo(conf, from_udev, NULL, + DI_SYSFS | DI_WWID | DI_BLACKLIST, + &from_pp, PATHFLAG_UID_TO_BE_REFERENCED); + put_multipath_config(conf); + + if (!from_pp || ret) { + condlog(3, "%s: (%s) failed to get source device (%s)\'s wwid", + pp->dev, msg_id, from_dev); + goto out2; + } + + if (strlen(from_pp->wwid) != 0) { + len = strlcpy(pp->wwid, from_pp->wwid, WWID_SIZE); + } +out2: + udev_device_unref(from_udev); +out1: + FREE(args); + + return len; +} + int get_uid (struct path * pp, int path_state, struct udev_device *udev) { @@ -1775,8 +1887,9 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) const char *origin = "unknown"; ssize_t len = 0; struct config *conf; + int flag; - if (!pp->uid_attribute && !pp->getuid) { + if (!pp->uid_attribute && !pp->getuid && !pp->uid_reference) { conf = get_multipath_config(); select_getuid(conf, pp); put_multipath_config(conf); @@ -1788,7 +1901,13 @@ get_uid (struct path * pp, int path_state, struct udev_device *udev) } memset(pp->wwid, 0, WWID_SIZE); - if (pp->getuid) { + + flag = pp->flags & PATHFLAG_UID_TO_BE_REFERENCED; + if (!flag && check_uid_reference(pp, pp->uid_reference) == 0) { + len = get_uid_reference(pp, pp->uid_reference); + origin = "reference"; + } + else if (pp->getuid) { char buff[CALLOUT_MAX_SIZE]; /* Use 'getuid' callout, deprecated */ diff --git a/libmultipath/propsel.c b/libmultipath/propsel.c index 27f39517..75c339c1 100644 --- a/libmultipath/propsel.c +++ b/libmultipath/propsel.c @@ -343,10 +343,35 @@ out: return 0; } +static int select_uid_reference(struct config *conf, struct path *pp) +{ + char *origin; + int flag = pp->flags & PATHFLAG_UID_TO_BE_REFERENCED; + + if (!flag) { + pp_set_ovr(uid_reference); + pp_set_hwe(uid_reference); + pp_set_conf(uid_reference); + } + +out: + if (pp->uid_reference) + condlog(3, "%s: uid_reference = %s %s", pp->dev, + pp->uid_reference, origin); + return 0; + +} + int select_getuid(struct config *conf, struct path *pp) { char *origin; + /* + * Here we use a wrapper to ensure uid_reference can be fetched + * with either getuid or uid_atrribute. + */ + select_uid_reference(conf, pp); + pp->uid_attribute = parse_uid_attribute_by_attrs(conf->uid_attrs, pp->dev); if (pp->uid_attribute) { origin = "(setting: multipath.conf defaults section)"; diff --git a/libmultipath/structs.h b/libmultipath/structs.h index 0d2bc40d..e548059d 100644 --- a/libmultipath/structs.h +++ b/libmultipath/structs.h @@ -222,6 +222,7 @@ struct path { int wait_checks; int tpgs; char * uid_attribute; + char * uid_reference; char * getuid; struct prio prio; char * prio_args; diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c index 22be8e0d..ed5c94df 100644 --- a/libmultipath/structs_vec.c +++ b/libmultipath/structs_vec.c @@ -85,6 +85,7 @@ void orphan_path(struct path *pp, const char *reason) pp->mpp = NULL; pp->dmstate = PSTATE_UNDEF; pp->uid_attribute = NULL; + pp->uid_reference = NULL; pp->getuid = NULL; prio_put(&pp->prio); checker_put(&pp->checker); diff --git a/multipath/multipath.conf.5 b/multipath/multipath.conf.5 index 0049cba7..e2916ac6 100644 --- a/multipath/multipath.conf.5 +++ b/multipath/multipath.conf.5 @@ -238,6 +238,22 @@ The default is: for NVME devices \fBID_WWN\fR . . .TP +.B uid_reference +The user defined attribute providing a unique path identifier by referencing +another path's identifier. Those paths can be coalesced. This is useful to +migrate data for heterogenous arrays without interrupting uplayer transaction. +If you are going to let sda, sdb and sdc use the unique path identifier of the sdd, +you can set uid_reference as: +.RS +.TP +\fBsd[a-c] sdd\fR +where the first parameter which can be regular expression is the target devices +to be assigned. The second parameter is the source device whose identifier will be +referenced by the target devices. The source device only support one device. +.RE +. +. +.TP .B getuid_callout (Superseded by \fIuid_attribute\fR) The default program and args to callout to obtain a unique path identifier. Should be specified with an absolute path. @@ -1193,6 +1209,8 @@ section: .TP .B uid_attribute .TP +.B uid_reference +.TP .B path_selector .TP .B path_checker @@ -1259,6 +1277,8 @@ the values are taken from the \fIdevices\fR or \fIdefaults\fR sections: .TP .B uid_attribute .TP +.B uid_reference +.TP .B getuid_callout .TP .B path_selector @@ -1323,8 +1343,23 @@ Multipath uses a \fIWorld Wide Identification\fR (WWID) to determine which paths belong to the same device. Each path presenting the same WWID is assumed to point to the same device. .LP -The WWID is generated by three methods (in the order of preference): +The WWID is generated by four methods (in the order of preference): .TP 17 +.B uid_reference +The user defined attribute providing a unique path identifier by referencing +another path's identifier. Those paths can be coalesced. This is useful to +migrate data for heterogenous arrays without interrupting uplayer transaction. +If you are going to let sda, sdb and sdc use the unique path identifier of the sdd, +you can set uid_reference as: +.RS +.TP +\fBsd[a-c] sdd\fR +where the first parameter which can be regular expression is the target devices +to be assigned. The second parameter is the source device whose identifier will be +referenced by the target devices. The source device only support one device. +.RE +. +.TP .B getuid_callout Use the specified external program; cf \fIgetuid_callout\fR above. Care should be taken when using this method; the external program