diff mbox

[07/12] Make multipathd orphan paths that were removed externally

Message ID 1404105243-5071-8-git-send-email-bmarzins@redhat.com (mailing list archive)
State Accepted, archived
Delegated to: christophe varoqui
Headers show

Commit Message

Benjamin Marzinski June 30, 2014, 5:13 a.m. UTC
Multipathd was only orphaning paths that it removed, not ones that were
removed by the multipath command.  This could cause problems if a path
was failed but not removed, and "multipath -r" was run.  multipath would
remove the path, and when multipathd updated itself, it would remove
that path from the multipath device's path list, but not orphan it.
When the path became active again, multipathd crashed trying to adjust
the pathgroups of the multipath device it had previously belonged to.

This patch makes sure that whenever multipathd updates the multipath device
table, it first makes sure the mpp->paths is uptodate.  Once it has
finished updating the device table, it orphans any paths in mpp->paths
that are no longer part of the multipath device.

Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
---
 libmultipath/structs_vec.c | 31 +++++++++++++++++++++++++++----
 multipathd/main.c          |  4 ++++
 2 files changed, 31 insertions(+), 4 deletions(-)

Comments

Christophe Varoqui July 24, 2014, 8:41 a.m. UTC | #1
Applied,
Thanks.


On Mon, Jun 30, 2014 at 7:13 AM, Benjamin Marzinski <bmarzins@redhat.com>
wrote:

> Multipathd was only orphaning paths that it removed, not ones that were
> removed by the multipath command.  This could cause problems if a path
> was failed but not removed, and "multipath -r" was run.  multipath would
> remove the path, and when multipathd updated itself, it would remove
> that path from the multipath device's path list, but not orphan it.
> When the path became active again, multipathd crashed trying to adjust
> the pathgroups of the multipath device it had previously belonged to.
>
> This patch makes sure that whenever multipathd updates the multipath device
> table, it first makes sure the mpp->paths is uptodate.  Once it has
> finished updating the device table, it orphans any paths in mpp->paths
> that are no longer part of the multipath device.
>
> Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
> ---
>  libmultipath/structs_vec.c | 31 +++++++++++++++++++++++++++----
>  multipathd/main.c          |  4 ++++
>  2 files changed, 31 insertions(+), 4 deletions(-)
>
> diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
> index 8cdbe3d..23f5bbb 100644
> --- a/libmultipath/structs_vec.c
> +++ b/libmultipath/structs_vec.c
> @@ -281,12 +281,38 @@ update_multipath_status (struct multipath *mpp)
>         return 0;
>  }
>
> +void sync_paths(struct multipath *mpp, vector pathvec)
> +{
> +       struct path *pp;
> +       struct pathgroup  *pgp;
> +       int found, i, j;
> +
> +       vector_foreach_slot (mpp->paths, pp, i) {
> +               found = 0;
> +               vector_foreach_slot(mpp->pg, pgp, j) {
> +                       if (find_slot(pgp->paths, (void *)pp) != -1) {
> +                               found = 1;
> +                               break;
> +                       }
> +               }
> +               if (!found) {
> +                       condlog(3, "%s dropped path %s", mpp->alias,
> pp->dev);
> +                       vector_del_slot(mpp->paths, i--);
> +                       orphan_path(pp, "path removed externally");
> +               }
> +       }
> +       update_mpp_paths(mpp, pathvec);
> +       vector_foreach_slot (mpp->paths, pp, i)
> +               pp->mpp = mpp;
> +}
> +
>  extern int
>  update_multipath_strings (struct multipath *mpp, vector pathvec)
>  {
>         if (!mpp)
>                 return 1;
>
> +       update_mpp_paths(mpp, pathvec);
>         condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
>
>         free_multipath_attributes(mpp);
> @@ -295,6 +321,7 @@ update_multipath_strings (struct multipath *mpp,
> vector pathvec)
>
>         if (update_multipath_table(mpp, pathvec))
>                 return 1;
> +       sync_paths(mpp, pathvec);
>
>         if (update_multipath_status(mpp))
>                 return 1;
> @@ -508,13 +535,9 @@ int update_multipath (struct vectors *vecs, char
> *mapname, int reset)
>                 return 2;
>         }
>
> -       free_pgvec(mpp->pg, KEEP_PATHS);
> -       mpp->pg = NULL;
> -
>         if (__setup_multipath(vecs, mpp, reset))
>                 return 1; /* mpp freed in setup_multipath */
>
> -       adopt_paths(vecs->pathvec, mpp, 0);
>         /*
>          * compare checkers states with DM states
>          */
> diff --git a/multipathd/main.c b/multipathd/main.c
> index 56d00d3..337bfe9 100644
> --- a/multipathd/main.c
> +++ b/multipathd/main.c
> @@ -1170,6 +1170,10 @@ check_path (struct vectors * vecs, struct path * pp)
>                         pp->dev);
>                 pp->dmstate = PSTATE_UNDEF;
>         }
> +       /* if update_multipath_strings orphaned the path, quit early */
> +       if (!pp->mpp)
> +               return 0;
> +
>         pp->chkrstate = newstate;
>         if (newstate != pp->state) {
>                 int oldstate = pp->state;
> --
> 1.8.3.1
>
>
--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
diff mbox

Patch

diff --git a/libmultipath/structs_vec.c b/libmultipath/structs_vec.c
index 8cdbe3d..23f5bbb 100644
--- a/libmultipath/structs_vec.c
+++ b/libmultipath/structs_vec.c
@@ -281,12 +281,38 @@  update_multipath_status (struct multipath *mpp)
 	return 0;
 }
 
+void sync_paths(struct multipath *mpp, vector pathvec)
+{
+	struct path *pp;
+	struct pathgroup  *pgp;
+	int found, i, j;
+
+	vector_foreach_slot (mpp->paths, pp, i) {
+		found = 0;
+		vector_foreach_slot(mpp->pg, pgp, j) {
+			if (find_slot(pgp->paths, (void *)pp) != -1) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found) {
+			condlog(3, "%s dropped path %s", mpp->alias, pp->dev);
+			vector_del_slot(mpp->paths, i--);
+			orphan_path(pp, "path removed externally");
+		}
+	}
+	update_mpp_paths(mpp, pathvec);
+	vector_foreach_slot (mpp->paths, pp, i)
+		pp->mpp = mpp;
+}
+
 extern int
 update_multipath_strings (struct multipath *mpp, vector pathvec)
 {
 	if (!mpp)
 		return 1;
 
+	update_mpp_paths(mpp, pathvec);
 	condlog(4, "%s: %s", mpp->alias, __FUNCTION__);
 
 	free_multipath_attributes(mpp);
@@ -295,6 +321,7 @@  update_multipath_strings (struct multipath *mpp, vector pathvec)
 
 	if (update_multipath_table(mpp, pathvec))
 		return 1;
+	sync_paths(mpp, pathvec);
 
 	if (update_multipath_status(mpp))
 		return 1;
@@ -508,13 +535,9 @@  int update_multipath (struct vectors *vecs, char *mapname, int reset)
 		return 2;
 	}
 
-	free_pgvec(mpp->pg, KEEP_PATHS);
-	mpp->pg = NULL;
-
 	if (__setup_multipath(vecs, mpp, reset))
 		return 1; /* mpp freed in setup_multipath */
 
-	adopt_paths(vecs->pathvec, mpp, 0);
 	/*
 	 * compare checkers states with DM states
 	 */
diff --git a/multipathd/main.c b/multipathd/main.c
index 56d00d3..337bfe9 100644
--- a/multipathd/main.c
+++ b/multipathd/main.c
@@ -1170,6 +1170,10 @@  check_path (struct vectors * vecs, struct path * pp)
 			pp->dev);
 		pp->dmstate = PSTATE_UNDEF;
 	}
+	/* if update_multipath_strings orphaned the path, quit early */
+	if (!pp->mpp)
+		return 0;
+
 	pp->chkrstate = newstate;
 	if (newstate != pp->state) {
 		int oldstate = pp->state;