fix coredump and memory leak in long-term stability test

(cherry picked from commit 28aa54fd3d7e08c448d00f91aa809468e3f78e43)
This commit is contained in:
Lixiaokeng 2022-04-08 10:27:09 +08:00 committed by openeuler-sync-bot
parent d979e09c29
commit ba65a51864
5 changed files with 294 additions and 1 deletions

View File

@ -0,0 +1,86 @@
From 11e3f4d3ce82fad0d324f220e8339deed13f1e56 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 13 Jul 2020 13:07:40 +0200
Subject: [PATCH] clear path in mpp->pg in clear_ref_from_mpp
When multipathd del path xxx, multipathd -v2, multipathd add path xxx and multipath -U
dm-x are executed simultaneously, multipath -U dm-x will case coredump.
The reason is that there are two paths with same dev_t in dm_table. The process
is as follows:
multipathd del path xxx(such as sde whose dev_t is 8:64):
cli_del_path
->ev_remove_path
->domap //dm_table in kernel will be reloaded and doesn't contain 8:64.
//Then multipath -v2 is executed, and the dm_table in kernel
//will be reloaded and contains 8:64.
->setup_multipath
->update_multipath_strings
->update_multipath_table
->dm_get_map //get params with 8:64
->disassemble_map //pp1 will be saved mpp->pg
->delete pp1 in pathvec
->clear_ref_from_mpp //pp is cleared in mpp->paths but still saved in
//mpp->pg
->free_paths //pp1 is freed but still exist in mpp->pg and is not null
multipathd add path sde
cli_add_path
->store_pathinfo //alloc pp2 (dev_t is 8:64), and store it to gvecs->pathvec
//pp2 is not equal to pp1
->ev_add_path
->adopt_paths
->update_mpp_paths //pp1 is found in mpp->pg and its dev_t is
//8:64 and dev is not sde (cased by free).
//it will be stored in mpp->paths.
->pp2 is stored to mpp->paths
->setup_map //params with two 8:64
->domap //dm_table is reloaded and contains two 8:64
multipath -U dm-x(sde is one path of dm-x)
main
->check_usable_paths
->dm_get_maps //get params with two 8:64
->disassemble_map //alloc pp3 whose dev_t is 8:64, and pp3 is saved
//twice in mpp->pg
->free_multipath(mpp, FREE_PATHS) //double free pp3
Here, we add that pp1 in mpp->pg is cleared in clear_ref_from_mpp.
Reported-by: Tianxiong Lu <lutianxiong@huawei.com>
Signed-off-by: lixiaokeng <lixiaokeng@huawei.com>
---
multipathd/main.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/multipathd/main.c b/multipathd/main.c
index 09ea102..e7e176b 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -845,7 +845,9 @@ static
void clear_ref_from_mpp(struct path * pp, struct vectors * vecs)
{
struct multipath * mpp = NULL;
+ struct pathgroup * pgp;
int i = -1;
+ int j;
mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
if(!!mpp){
@@ -853,6 +855,11 @@ void clear_ref_from_mpp(struct path * pp, struct vectors * vecs)
if ((i = find_slot(mpp->paths, (void *)pp)) != -1){
vector_del_slot(mpp->paths, i);
}
+ vector_foreach_slot (mpp->pg, pgp, j) {
+ if ((i = find_slot(pgp->paths, (void *)pp)) != -1){
+ vector_del_slot(pgp->paths, i);
+ }
+ }
}
}
--
2.14.3 (Apple Git-98)

View File

@ -0,0 +1,56 @@
From 0b0062058ef0bcf2a80194700ed20304d4445854 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 13 Jul 2020 13:07:40 +0200
Subject: [PATCH] multipathd: fix mpp->hwe use after free in ev_remove_path
When a multipath device (for example mpatha) has only one path
and it can't flush because of occupation, "multipathd del path"
and "multipath -v2" may lead to multipathd coredump. The reason
is that mpp->hwe = pp->hwe but pp->hwe will be free later. Here
we clear mpp->hwe in clear_ref_from_mpp.
Signed-off-by: Lixiaokeng <lixiaokeng@huawei.com>
---
multipathd/main.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/multipathd/main.c b/multipathd/main.c
index e7e176b..1c02441 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -850,17 +850,23 @@ void clear_ref_from_mpp(struct path * pp, struct vectors * vecs)
int j;
mpp = find_mp_by_wwid(vecs->mpvec, pp->wwid);
- if(!!mpp){
- condlog(2, "%s: clear path from mpp %s", pp->dev, mpp->alias);
- if ((i = find_slot(mpp->paths, (void *)pp)) != -1){
- vector_del_slot(mpp->paths, i);
- }
- vector_foreach_slot (mpp->pg, pgp, j) {
- if ((i = find_slot(pgp->paths, (void *)pp)) != -1){
- vector_del_slot(pgp->paths, i);
- }
+ if (!mpp) {
+ return;
+ }
+
+ condlog(2, "%s: clear path from mpp %s", pp->dev, mpp->alias);
+ if (mpp->hwe == pp->hwe) {
+ mpp->hwe = NULL;
+ }
+ if ((i = find_slot(mpp->paths, (void *)pp)) != -1) {
+ vector_del_slot(mpp->paths, i);
+ }
+ vector_foreach_slot(mpp->pg, pgp, j) {
+ if ((i = find_slot(pgp->paths, (void *)pp)) != -1) {
+ vector_del_slot(pgp->paths, i);
}
}
+ extract_hwe_from_path(mpp);
}
static int
--
2.14.3 (Apple Git-98)

View File

@ -0,0 +1,82 @@
From cb7441c91c27c685ea47043a0eab20c1eb56206e Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 13 Jul 2020 13:07:40 +0200
Subject: [PATCH] libmultipath: fix daemon memory leak in disassemble_map
When one iscsi device logs in and logs out with the "multipath -r"
executed at the same time, memory leak happens in multipathd
process.
The reason is following. When "multipath -r" is executed, the path
will be free in configure function. Before path_discovery executed,
iscsi device logs out. Then path_discovery will not find any path and
there is no path in the gvecs->pathvec. When map_discovery function
is executed, disassemble_map function will be called. Because
gvecs->pathvec->slot is empty and is_deamon is 1, a path will be
allocated and is not stored in gvecs->pathvec but store in
mpp->pg. But when the mpp is removed and freed by remove_map
function, the path will not be free and can't be find anymore.
The procedure details given as follows,
1."multipath -r" is executed
main
->child
->reconfigure
->configure
->path_discovery //after iscsi logout
->map_discovery
->update_multipath_table
->disassemble_map
->alloc_path
2.then "multipath -r" is executed again
main
->child
->reconfigure
->remove_maps_and_stop_waiters
->remove_maps
Here, we skip alloc_path if pp isn't find in pathvec and process is daemon. In
daemon, we should not store path with incomplete information to pathvec. The
pathvec stores all paths in daemon, so it is reasonable keep same with pathvec.
Reported-by: Tianxiong Lu <lutianxiong@huawei.com>
Signed-off-by: Lixiaokeng <lixiaokeng@huawei.com>
Signed-off-by: Zhiqiang Liu <liuzhiqiang26@huawei.com>
---
libmultipath/dmparser.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 7da5fbf..3ce6eb3 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -305,6 +305,16 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
}
if (!pp) {
+ /* daemon should keep same with pathvec */
+ /* pp is not find in pathvec, skip it */
+ if (is_daemon) {
+ FREE(word);
+ for (k = 0; k < num_paths_args; k++) {
+ p += get_word(p, NULL);
+ }
+ continue;
+ }
+
pp_unfound = 1;
pp = alloc_path();
@@ -317,8 +327,7 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
strlcpy(pp->wwid, mpp->wwid,
WWID_SIZE);
}
- /* Only call this in multipath client mode */
- if (!is_daemon && store_path(pathvec, pp)) {
+ if (store_path(pathvec, pp)) {
free_path(pp);
goto out1;
}
--
2.14.3 (Apple Git-98)

View File

@ -0,0 +1,62 @@
From 72816e34d2e4a3197e4a590e573c4fc64a360145 Mon Sep 17 00:00:00 2001
From: lixiaokeng <lixiaokeng@huawei.com>
Date: Mon, 13 Jul 2020 13:07:40 +0200
Subject: [PATCH] libmultipath: fix multipathd coredump in disassemble_map
Coredump appears when events are executed in a certain order.
1. The sdc and sdd are added as paths of d1. The sdc is added
firstly and d1->wait_for_udev be set to 1. Then sdd is added but
it just adds to pathvec because d1->wait_for_udev is 1.
2. The uev_remove_path(sdc) are executed. Because d1 has one
path, d1 will be flushed.
3. The uev_add_path(sdc) are executed. Now sdc and sdd will
both add to d1 in adopt_paths because sdd->wwid is d1. And
d1->wait_for_udev be set to 1.
4. The uev_remove_path(sdd) are executed. Because d1->wait_for_udev
is 1, domap doesn't executed and the major:minor of sdd(8:64)
still exist in kernel d1. The sdd in pathvec is deleted.
5. The uev_add_path(sdd) are executed. Now the sdd(8:64) is
a path of d2. And new sdd is added to pathvec.
6. The update_multipath_strings(d1) are executed. The d1 find
sdd in pathvec by dev_t(8:64and sdd will be add to d1. Now
the pointer of sdd is store in paths of d1 and d2.
7. When NIC is down and a new path add to d1, sdd will be freed
in verify_paths (because sdd is actually a path of d2).
8. When d2->hwe is sdd->hwe and setup_map(d2) is called. Core
causes.
The path shouldn't be add to the mpp whose wwid is different
with its. Here we add wwid check in disassemble_map. This bug
has been solved in upstream in update_pathvec_from_dm. It is
a great change, so we fix it with huawei patch. This patch could
be discarded when multipath-tools update.
Signed-off-by:lixiaokeng<lixiaokeng@huawei.com>
---
libmultipath/dmparser.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/libmultipath/dmparser.c b/libmultipath/dmparser.c
index 3ce6eb3..9aa6bc5 100644
--- a/libmultipath/dmparser.c
+++ b/libmultipath/dmparser.c
@@ -332,6 +332,16 @@ int disassemble_map(vector pathvec, char *params, struct multipath *mpp,
goto out1;
}
} else {
+ if (strlen(pp->wwid) && strlen(mpp->wwid) &&
+ strcmp(pp->wwid, mpp->wwid) != 0) {
+ condlog(0, "%s: path wwid is different with that of %s.\n", pp->dev_t, mpp->alias);
+ FREE(word);
+ for (k = 0; k < num_paths_args; k++) {
+ p += get_word(p, NULL);
+ }
+ continue;
+ }
+
if (!strlen(pp->wwid) &&
strlen(mpp->wwid))
strlcpy(pp->wwid, mpp->wwid,
--
2.14.3 (Apple Git-98)

View File

@ -2,7 +2,7 @@
Name: multipath-tools
Version: 0.8.4
Release: 13
Release: 14
Summary: Tools to manage multipath devices with the device-mapper
License: GPL-2.0-or-later and LGPL-2.0-only
URL: http://christophe.varoqui.free.fr/
@ -38,6 +38,10 @@ Patch25: 0025-fix-boolean-value-with-json-c-0.14.patch
Patch26: 0026-multipath-tools-tests-directio-fix-Wmaybe-uninitaliz.patch
Patch27: 0027-libmultipath-refactor-path-counting.patch
Patch28: 0028-libmultipath-count-pending-paths-as-active-on-loads.patch
Patch29: 0029-clear-path-in-mpp-pg-in-clear_ref_from_mpp.patch
Patch30: 0030-multipathd-fix-mpp-hwe-use-after-free-in-ev_remove_p.patch
Patch31: 0031-libmultipath-fix-daemon-memory-leak-in-disassemble_m.patch
Patch32: 0032-libmultipath-fix-multipathd-coredump-in-disassemble_.patch
BuildRequires: multipath-tools, libcmocka, libcmocka-devel
BuildRequires: gcc, libaio-devel, userspace-rcu-devel, device-mapper-devel >= 1.02.89
@ -184,6 +188,9 @@ fi
%changelog
* Fri Apr 8 2022 lixiaokeng<lixiaokeng@huawei.com> - 0.8.4-14
- fix coredump and memory leak in long-term stability test
* Tue Mar 8 2022 lixiaokeng<lixiaokeng@huawei.com> - 0.8.4-13
- don't create local nvme multipath device when enable remove_local_path