diff mbox series

[libubootenv] Dont store to device if no value changes

Message ID 20200729193627.22906-1-liu.ming50@gmail.com
State Changes Requested
Headers show
Series [libubootenv] Dont store to device if no value changes | expand

Commit Message

Ming Liu July 29, 2020, 7:36 p.m. UTC
From: Ming Liu <liu.ming50@gmail.com>

When fw_setenv is called, it could happen that the new value is same
with the old one, in which case, we should avoid storing data to
device.

Signed-off-by: Ming Liu <liu.ming50@gmail.com>
---
 src/fw_printenv.c | 11 ++++++++---
 src/uboot_env.c   | 12 ++++++++++--
 2 files changed, 18 insertions(+), 5 deletions(-)

Comments

Stefano Babic July 30, 2020, 8:46 a.m. UTC | #1
Hi Ming,

On 29.07.20 21:36, liu.ming50@gmail.com wrote:
> From: Ming Liu <liu.ming50@gmail.com>
> 
> When fw_setenv is called, it could happen that the new value is same
> with the old one, in which case, we should avoid storing data to
> device.
> 

Just note that this is different as in the past, because old tools
always wrote to flash. But agree we can add the feature, please just
extend the commit message with note about different behavior.

Some projects used to run "fw_setenv" twice to be sure that both
environemnt are identical. I do not think this was necessary, but again
just write a comment that it does not work as before.

> Signed-off-by: Ming Liu <liu.ming50@gmail.com>
> ---
>  src/fw_printenv.c | 11 ++++++++---
>  src/uboot_env.c   | 12 ++++++++++--
>  2 files changed, 18 insertions(+), 5 deletions(-)
> 
> diff --git a/src/fw_printenv.c b/src/fw_printenv.c
> index 18887f9..cabeae5 100644
> --- a/src/fw_printenv.c
> +++ b/src/fw_printenv.c
> @@ -151,17 +151,22 @@ int main (int argc, char **argv) {
>  			}
>  		}
>  	} else { /* setenv branch */
> +		bool ok_change = false, ok_write = false;
>  		if (scriptfile)
>  			libuboot_load_file(ctx, scriptfile);
>  		else {
>  			for (i = 0; i < argc; i += 2) {
>  				if (i + 1 == argc)
> -					libuboot_set_env(ctx, argv[i], NULL);

This is to *remove* a variable.

> +					ok_write = (libuboot_set_env(ctx, argv[i], NULL) == 0);
>  				else

No. You are changing the library API. It is legitime to call
libuboot_set_env() many times, even with the same value. The library
handles this and does not create multiple variables. Please note that
variables are just stored in memory. The caller of the library decide
when to store. So returning -EAGAIN is just a trick to be informed if
the value is the same (EAGAIN, why ?). Instead of this, I suggest to
make changes only in fw_printenv.c, that is by implementing a
read-modify-write approach.

- First, call libuboot_get_env()
- compare value, if differs call libuboot_set_env()
- mark if you need to save as you are doing it with a bool

> -					libuboot_set_env(ctx, argv[i], argv[i+1]);
> +					ok_write = (libuboot_set_env(ctx, argv[i], argv[i+1]) == 0);
> +				if (ok_write)
> +					ok_change = true;
>  			}
>  		}
> -		ret = libuboot_env_store(ctx);
> +
> +		if (ok_change)
> +			ret = libuboot_env_store(ctx);
>  		if (ret)
>  			fprintf(stderr, "Error storing the env\n");
>  	}
> diff --git a/src/uboot_env.c b/src/uboot_env.c
> index 25de4fb..c342931 100644
> --- a/src/uboot_env.c
> +++ b/src/uboot_env.c
> @@ -1242,8 +1242,16 @@ int libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *val
>  			if (!value) {
>  				free_var_entry(envs, entry);
>  			} else {
> -				free(entry->value);
> -				entry->value = strdup(value);
> +				if (strcmp(entry->value, value) == 0) {
> +#if !defined(NDEBUG)
> +					fprintf(stdout, "No change to parameter, old %s, new %s\n",
> +						entry->value, value);
> +#endif
> +					return -EAGAIN;

This change is not necessary and breaks API.

> +				} else {
> +					free(entry->value);
> +					entry->value = strdup(value);
> +				}
>  			}
>  			return 0;
>  		} else {
> 

Best regards,
Stefano Babic
Ming Liu July 30, 2020, 10:56 a.m. UTC | #2
Thanks for the review, will make a V2 as you suggested.

//Ming Liu

Stefano Babic <sbabic@denx.de> 於 2020年7月30日 週四 上午10:46寫道:

> Hi Ming,
>
> On 29.07.20 21:36, liu.ming50@gmail.com wrote:
> > From: Ming Liu <liu.ming50@gmail.com>
> >
> > When fw_setenv is called, it could happen that the new value is same
> > with the old one, in which case, we should avoid storing data to
> > device.
> >
>
> Just note that this is different as in the past, because old tools
> always wrote to flash. But agree we can add the feature, please just
> extend the commit message with note about different behavior.
>
> Some projects used to run "fw_setenv" twice to be sure that both
> environemnt are identical. I do not think this was necessary, but again
> just write a comment that it does not work as before.
>
> > Signed-off-by: Ming Liu <liu.ming50@gmail.com>
> > ---
> >  src/fw_printenv.c | 11 ++++++++---
> >  src/uboot_env.c   | 12 ++++++++++--
> >  2 files changed, 18 insertions(+), 5 deletions(-)
> >
> > diff --git a/src/fw_printenv.c b/src/fw_printenv.c
> > index 18887f9..cabeae5 100644
> > --- a/src/fw_printenv.c
> > +++ b/src/fw_printenv.c
> > @@ -151,17 +151,22 @@ int main (int argc, char **argv) {
> >                       }
> >               }
> >       } else { /* setenv branch */
> > +             bool ok_change = false, ok_write = false;
> >               if (scriptfile)
> >                       libuboot_load_file(ctx, scriptfile);
> >               else {
> >                       for (i = 0; i < argc; i += 2) {
> >                               if (i + 1 == argc)
> > -                                     libuboot_set_env(ctx, argv[i],
> NULL);
>
> This is to *remove* a variable.
>
> > +                                     ok_write = (libuboot_set_env(ctx,
> argv[i], NULL) == 0);
> >                               else
>
> No. You are changing the library API. It is legitime to call
> libuboot_set_env() many times, even with the same value. The library
> handles this and does not create multiple variables. Please note that
> variables are just stored in memory. The caller of the library decide
> when to store. So returning -EAGAIN is just a trick to be informed if
> the value is the same (EAGAIN, why ?). Instead of this, I suggest to
> make changes only in fw_printenv.c, that is by implementing a
> read-modify-write approach.
>
> - First, call libuboot_get_env()
> - compare value, if differs call libuboot_set_env()
> - mark if you need to save as you are doing it with a bool
>
> > -                                     libuboot_set_env(ctx, argv[i],
> argv[i+1]);
> > +                                     ok_write = (libuboot_set_env(ctx,
> argv[i], argv[i+1]) == 0);
> > +                             if (ok_write)
> > +                                     ok_change = true;
> >                       }
> >               }
> > -             ret = libuboot_env_store(ctx);
> > +
> > +             if (ok_change)
> > +                     ret = libuboot_env_store(ctx);
> >               if (ret)
> >                       fprintf(stderr, "Error storing the env\n");
> >       }
> > diff --git a/src/uboot_env.c b/src/uboot_env.c
> > index 25de4fb..c342931 100644
> > --- a/src/uboot_env.c
> > +++ b/src/uboot_env.c
> > @@ -1242,8 +1242,16 @@ int libuboot_set_env(struct uboot_ctx *ctx, const
> char *varname, const char *val
> >                       if (!value) {
> >                               free_var_entry(envs, entry);
> >                       } else {
> > -                             free(entry->value);
> > -                             entry->value = strdup(value);
> > +                             if (strcmp(entry->value, value) == 0) {
> > +#if !defined(NDEBUG)
> > +                                     fprintf(stdout, "No change to
> parameter, old %s, new %s\n",
> > +                                             entry->value, value);
> > +#endif
> > +                                     return -EAGAIN;
>
> This change is not necessary and breaks API.
>
> > +                             } else {
> > +                                     free(entry->value);
> > +                                     entry->value = strdup(value);
> > +                             }
> >                       }
> >                       return 0;
> >               } else {
> >
>
> Best regards,
> Stefano Babic
>
> --
> =====================================================================
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: +49-8142-66989-53 Fax: +49-8142-66989-80 Email: sbabic@denx.de
> =====================================================================
>
diff mbox series

Patch

diff --git a/src/fw_printenv.c b/src/fw_printenv.c
index 18887f9..cabeae5 100644
--- a/src/fw_printenv.c
+++ b/src/fw_printenv.c
@@ -151,17 +151,22 @@  int main (int argc, char **argv) {
 			}
 		}
 	} else { /* setenv branch */
+		bool ok_change = false, ok_write = false;
 		if (scriptfile)
 			libuboot_load_file(ctx, scriptfile);
 		else {
 			for (i = 0; i < argc; i += 2) {
 				if (i + 1 == argc)
-					libuboot_set_env(ctx, argv[i], NULL);
+					ok_write = (libuboot_set_env(ctx, argv[i], NULL) == 0);
 				else
-					libuboot_set_env(ctx, argv[i], argv[i+1]);
+					ok_write = (libuboot_set_env(ctx, argv[i], argv[i+1]) == 0);
+				if (ok_write)
+					ok_change = true;
 			}
 		}
-		ret = libuboot_env_store(ctx);
+
+		if (ok_change)
+			ret = libuboot_env_store(ctx);
 		if (ret)
 			fprintf(stderr, "Error storing the env\n");
 	}
diff --git a/src/uboot_env.c b/src/uboot_env.c
index 25de4fb..c342931 100644
--- a/src/uboot_env.c
+++ b/src/uboot_env.c
@@ -1242,8 +1242,16 @@  int libuboot_set_env(struct uboot_ctx *ctx, const char *varname, const char *val
 			if (!value) {
 				free_var_entry(envs, entry);
 			} else {
-				free(entry->value);
-				entry->value = strdup(value);
+				if (strcmp(entry->value, value) == 0) {
+#if !defined(NDEBUG)
+					fprintf(stdout, "No change to parameter, old %s, new %s\n",
+						entry->value, value);
+#endif
+					return -EAGAIN;
+				} else {
+					free(entry->value);
+					entry->value = strdup(value);
+				}
 			}
 			return 0;
 		} else {