diff mbox

[15/28] libmultipath: merge hwentries inside a conf file

Message ID 20180608102041.22904-16-mwilck@suse.com (mailing list archive)
State Not Applicable, archived
Delegated to: christophe varoqui
Headers show

Commit Message

Martin Wilck June 8, 2018, 10:20 a.m. UTC
Merging hwentries with identical vendor/product/revision is still useful,
although it's not strictly necessary any more. But such identical entries
should always be merged, not only if they appear in different configuration
files. This requires changing the logic of factorize_hwtable.

By setting -DCHECK_BUILTIN_HWTABLE at compile time, the built-in hwtable
can be checked against duplicates as well.

Signed-off-by: Martin Wilck <mwilck@suse.com>
---
 libmultipath/config.c | 43 +++++++++++++++++++++----------------------
 1 file changed, 21 insertions(+), 22 deletions(-)

Comments

Benjamin Marzinski June 15, 2018, 6:03 p.m. UTC | #1
On Fri, Jun 08, 2018 at 12:20:28PM +0200, Martin Wilck wrote:
> Merging hwentries with identical vendor/product/revision is still useful,
> although it's not strictly necessary any more. But such identical entries
> should always be merged, not only if they appear in different configuration
> files. This requires changing the logic of factorize_hwtable.

Sorry for my slowness in reviewing these. This one looks wrong to me
 
> By setting -DCHECK_BUILTIN_HWTABLE at compile time, the built-in hwtable
> can be checked against duplicates as well.
> 
> Signed-off-by: Martin Wilck <mwilck@suse.com>
> ---
>  libmultipath/config.c | 43 +++++++++++++++++++++----------------------
>  1 file changed, 21 insertions(+), 22 deletions(-)
> 
> diff --git a/libmultipath/config.c b/libmultipath/config.c
> index 713ac7f3..fb41d620 100644
> --- a/libmultipath/config.c
> +++ b/libmultipath/config.c
> @@ -452,7 +452,7 @@ out:
>  }
>  
>  static void
> -factorize_hwtable (vector hw, int n)
> +factorize_hwtable (vector hw, int n, const char *table_desc)
>  {
>  	struct hwentry *hwe1, *hwe2;
>  	int i, j;
> @@ -462,22 +462,26 @@ restart:
>  		if (i == n)
>  			break;
>  		j = n;
> +		/* drop invalid device configs */
> +		if (i >= n && (!hwe1->vendor || !hwe1->product)) {

How can i >= n?  vector_foreach_slot() starts i at 0, and then next
lines are

                if (i == n)
                        break;


> +			condlog(0, "device config in %s missing vendor or product parameter",
> +				table_desc);
> +			vector_del_slot(hw, i--);

shouldn't we also decrement n here. I realize that doesn't work well for
the CHECK_BUILTIN_HWTABLE check, where n is 0, but as I said above, I'm
pretty sure that will never get here.

> +			free_hwe(hwe1);
> +			continue;
> +		}
> +		j = n > i + 1 ? n : i + 1;

again, n must always be at least i + 1 to get here, so j is always n.

>  		vector_foreach_slot_after(hw, hwe2, j) {
> -			/* drop invalid device configs */
> -			if (!hwe2->vendor || !hwe2->product) {
> -				condlog(0, "device config missing vendor or product parameter");
> -				vector_del_slot(hw, j--);
> -				free_hwe(hwe2);
> -				continue;
> -			}
>  			if (hwe_strmatch(hwe2, hwe1) == 0) {
> -				condlog(4, "%s: removing hwentry %s:%s:%s",
> +				condlog(i >= n ? 1 : 3,

this check also looks wrong

> +					"%s: duplicate device section for %s:%s:%s in %s",
>  					__func__, hwe1->vendor, hwe1->product,
> -					hwe1->revision);
> +					hwe1->revision, table_desc);
>  				vector_del_slot(hw, i);
>  				merge_hwe(hwe2, hwe1);
>  				free_hwe(hwe1);
> -				n -= 1;
> +				if (i < n)

and this one looks unnecessary.

> +					n -= 1;
>  				/*
>  				 * Play safe here; we have modified
>  				 * the original vector so the outer
> @@ -605,9 +609,8 @@ process_config_dir(struct config *conf, vector keywords, char *dir)
>  		snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
>  		path[LINE_MAX-1] = '\0';
>  		process_file(conf, path);
> -		if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
> -			factorize_hwtable(conf->hwtable, old_hwtable_size);
> -
> +		factorize_hwtable(conf->hwtable, old_hwtable_size,
> +				  namelist[i]->d_name);
>  	}
>  	pthread_cleanup_pop(1);
>  }
> @@ -655,6 +658,9 @@ load_config (char * file)
>  	if (setup_default_hwtable(conf->hwtable))
>  		goto out;
>  
> +#ifdef CHECK_BUILTIN_HWTABLE
> +	factorize_hwtable(conf->hwtable, 0, "builtin");
> +#endif
>  	/*
>  	 * read the config file
>  	 */
> @@ -668,14 +674,7 @@ load_config (char * file)
>  			condlog(0, "error parsing config file");
>  			goto out;
>  		}
> -		if (VECTOR_SIZE(conf->hwtable) > builtin_hwtable_size) {
> -			/*
> -			 * remove duplica in hwtable. config file
> -			 * takes precedence over build-in hwtable
> -			 */
> -			factorize_hwtable(conf->hwtable, builtin_hwtable_size);
> -		}
> -
> +		factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
>  	}
>  
>  	conf->processed_main_config = 1;
> -- 
> 2.17.0

--
dm-devel mailing list
dm-devel@redhat.com
https://www.redhat.com/mailman/listinfo/dm-devel
Martin Wilck June 18, 2018, 9:33 a.m. UTC | #2
Hi Ben,

On Fri, 2018-06-15 at 13:03 -0500, Benjamin Marzinski wrote:
> On Fri, Jun 08, 2018 at 12:20:28PM +0200, Martin Wilck wrote:
> > Merging hwentries with identical vendor/product/revision is still
> > useful,
> > although it's not strictly necessary any more. But such identical
> > entries
> > should always be merged, not only if they appear in different
> > configuration
> > files. This requires changing the logic of factorize_hwtable.
> 
> Sorry for my slowness in reviewing these. This one looks wrong to me

Thanks for the thorough review. Given the size of the series, I don't
think this was slow.
 
> > By setting -DCHECK_BUILTIN_HWTABLE at compile time, the built-in
> > hwtable
> > can be checked against duplicates as well.
> > 
> > Signed-off-by: Martin Wilck <mwilck@suse.com>
> > ---
> >  libmultipath/config.c | 43 +++++++++++++++++++++----------------
> > ------
> >  1 file changed, 21 insertions(+), 22 deletions(-)
> > 
> > diff --git a/libmultipath/config.c b/libmultipath/config.c
> > index 713ac7f3..fb41d620 100644
> > --- a/libmultipath/config.c
> > +++ b/libmultipath/config.c
> > @@ -452,7 +452,7 @@ out:
> >  }
> >  
> >  static void
> > -factorize_hwtable (vector hw, int n)
> > +factorize_hwtable (vector hw, int n, const char *table_desc)
> >  {
> >  	struct hwentry *hwe1, *hwe2;
> >  	int i, j;
> > @@ -462,22 +462,26 @@ restart:
> >  		if (i == n)
> >  			break;
> >  		j = n;
> > +		/* drop invalid device configs */
> > +		if (i >= n && (!hwe1->vendor || !hwe1->product)) {
> 
> How can i >= n?  vector_foreach_slot() starts i at 0, and then next
> lines are
> 
>                 if (i == n)
>                         break;

The above two lines, and the line "j = n" after that, were meant to be
deleted. That slipped through in my rebasing work, sorry about that.
When these lines are gone, I believe your issues are resolved, see
below.

n denotes the number of hwentries present before the current config
file was parsed. Before my patch series, "factorize_hwtable" would only
check for duplicates between the "old" (i < n) and "new" (i >= n)
sections, and would not remove the dups inside either section. Now
duplicates are also merged if they occur in the same section (except
for the built-in hwtable, for which the "inside" check is only done
with -DCHECK_BUILTIN_HWTABLE).

Well - that's what I intended to do, but by by forgetting to delete the
above lines, I failed :-(

In practice, this error only breaks the "broken hwentry" and "dup
removal inside a section" features - application of "good" hwentries to
paths and multipaths isn't affected, and thus the test cases pass
despite the bug. I'll post a fix, plus new test cases covering it.

> > +			condlog(0, "device config in %s missing
> > vendor or product parameter",
> > +				table_desc);
> > +			vector_del_slot(hw, i--);
> 
> shouldn't we also decrement n here. I realize that doesn't work well
> for
> the CHECK_BUILTIN_HWTABLE check, where n is 0, but as I said above,
> I'm
> pretty sure that will never get here.

No, see above. The check for broken entries is only done for "new" ones
(i > n), as we assume the entries up to n to be checked already. So
when we reach this condition, is is really always above n.

> 
> > +			free_hwe(hwe1);
> > +			continue;
> > +		}
> > +		j = n > i + 1 ? n : i + 1;
> 
> again, n must always be at least i + 1 to get here, so j is always n.

See above.

> 
> >  		vector_foreach_slot_after(hw, hwe2, j) {
> > -			/* drop invalid device configs */
> > -			if (!hwe2->vendor || !hwe2->product) {
> > -				condlog(0, "device config missing
> > vendor or product parameter");
> > -				vector_del_slot(hw, j--);
> > -				free_hwe(hwe2);
> > -				continue;
> > -			}
> >  			if (hwe_strmatch(hwe2, hwe1) == 0) {
> > -				condlog(4, "%s: removing hwentry
> > %s:%s:%s",
> > +				condlog(i >= n ? 1 : 3,
> 
> this check also looks wrong

The intention is not to log at prio 1 if a new section (read in most
cases: multipath.conf) contains a duplicate to a previous section (read
in most cases: built-in hwtable). Such use is perfectly valid, whereas
two hwentries with the same vendor and product in one config file are
suspicious and should be logged.

> 
> > +					"%s: duplicate device
> > section for %s:%s:%s in %s",
> >  					__func__, hwe1->vendor,
> > hwe1->product,
> > -					hwe1->revision);
> > +					hwe1->revision,
> > table_desc);
> >  				vector_del_slot(hw, i);
> >  				merge_hwe(hwe2, hwe1);
> >  				free_hwe(hwe1);
> > -				n -= 1;
> > +				if (i < n)
> 
> and this one looks unnecessary.

See above.

I order to avoid spamming dm-devel with the whole series again, I'll
send patches on top of it. If you prefer that I send the full rebased
series, I'll do of course, but I'll wait for more reviews.

Thanks,
Martin
diff mbox

Patch

diff --git a/libmultipath/config.c b/libmultipath/config.c
index 713ac7f3..fb41d620 100644
--- a/libmultipath/config.c
+++ b/libmultipath/config.c
@@ -452,7 +452,7 @@  out:
 }
 
 static void
-factorize_hwtable (vector hw, int n)
+factorize_hwtable (vector hw, int n, const char *table_desc)
 {
 	struct hwentry *hwe1, *hwe2;
 	int i, j;
@@ -462,22 +462,26 @@  restart:
 		if (i == n)
 			break;
 		j = n;
+		/* drop invalid device configs */
+		if (i >= n && (!hwe1->vendor || !hwe1->product)) {
+			condlog(0, "device config in %s missing vendor or product parameter",
+				table_desc);
+			vector_del_slot(hw, i--);
+			free_hwe(hwe1);
+			continue;
+		}
+		j = n > i + 1 ? n : i + 1;
 		vector_foreach_slot_after(hw, hwe2, j) {
-			/* drop invalid device configs */
-			if (!hwe2->vendor || !hwe2->product) {
-				condlog(0, "device config missing vendor or product parameter");
-				vector_del_slot(hw, j--);
-				free_hwe(hwe2);
-				continue;
-			}
 			if (hwe_strmatch(hwe2, hwe1) == 0) {
-				condlog(4, "%s: removing hwentry %s:%s:%s",
+				condlog(i >= n ? 1 : 3,
+					"%s: duplicate device section for %s:%s:%s in %s",
 					__func__, hwe1->vendor, hwe1->product,
-					hwe1->revision);
+					hwe1->revision, table_desc);
 				vector_del_slot(hw, i);
 				merge_hwe(hwe2, hwe1);
 				free_hwe(hwe1);
-				n -= 1;
+				if (i < n)
+					n -= 1;
 				/*
 				 * Play safe here; we have modified
 				 * the original vector so the outer
@@ -605,9 +609,8 @@  process_config_dir(struct config *conf, vector keywords, char *dir)
 		snprintf(path, LINE_MAX, "%s/%s", dir, namelist[i]->d_name);
 		path[LINE_MAX-1] = '\0';
 		process_file(conf, path);
-		if (VECTOR_SIZE(conf->hwtable) > old_hwtable_size)
-			factorize_hwtable(conf->hwtable, old_hwtable_size);
-
+		factorize_hwtable(conf->hwtable, old_hwtable_size,
+				  namelist[i]->d_name);
 	}
 	pthread_cleanup_pop(1);
 }
@@ -655,6 +658,9 @@  load_config (char * file)
 	if (setup_default_hwtable(conf->hwtable))
 		goto out;
 
+#ifdef CHECK_BUILTIN_HWTABLE
+	factorize_hwtable(conf->hwtable, 0, "builtin");
+#endif
 	/*
 	 * read the config file
 	 */
@@ -668,14 +674,7 @@  load_config (char * file)
 			condlog(0, "error parsing config file");
 			goto out;
 		}
-		if (VECTOR_SIZE(conf->hwtable) > builtin_hwtable_size) {
-			/*
-			 * remove duplica in hwtable. config file
-			 * takes precedence over build-in hwtable
-			 */
-			factorize_hwtable(conf->hwtable, builtin_hwtable_size);
-		}
-
+		factorize_hwtable(conf->hwtable, builtin_hwtable_size, file);
 	}
 
 	conf->processed_main_config = 1;