From b9ac9a9785071f5d243cf287c527286624c08f1b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 15 Jul 2016 11:56:52 +0200 Subject: nv: Do not save nv variables while loading When reading nv variables from the storage in /env/nv we do not need to write back the value to the file we just read from. Optimize this a bit and make it unnecessary. Signed-off-by: Sascha Hauer --- common/globalvar.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) (limited to 'common') diff --git a/common/globalvar.c b/common/globalvar.c index c0958e11ea..be082314e7 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -180,15 +180,26 @@ static int nv_set(struct device_d *dev, struct param_d *p, const char *val) free(p->value); p->value = xstrdup(val); - return nv_save(p->name, val); + return 0; } -static const char *nv_get(struct device_d *dev, struct param_d *p) +static const char *nv_param_get(struct device_d *dev, struct param_d *p) { return p->value ? p->value : ""; } -int nvvar_add(const char *name, const char *value) +static int nv_param_set(struct device_d *dev, struct param_d *p, const char *val) +{ + int ret; + + ret = nv_set(dev, p, val); + if (ret) + return ret; + + return nv_save(p->name, val); +} + +static int __nvvar_add(const char *name, const char *value) { struct param_d *p, *gp; int ret; @@ -226,7 +237,7 @@ int nvvar_add(const char *name, const char *value) return ret; } - p = dev_add_param(&nv_device, name, nv_set, nv_get, 0); + p = dev_add_param(&nv_device, name, nv_param_set, nv_param_get, 0); if (IS_ERR(p)) return PTR_ERR(p); @@ -242,6 +253,17 @@ int nvvar_add(const char *name, const char *value) return nv_set(&nv_device, p, value); } +int nvvar_add(const char *name, const char *value) +{ + int ret; + + ret = __nvvar_add(name, value); + if (ret) + return ret; + + return nv_save(name, value); +} + int nvvar_remove(const char *name) { struct param_d *p; @@ -288,7 +310,7 @@ int nvvar_load(void) pr_debug("%s: Setting \"%s\" to \"%s\"\n", __func__, d->d_name, val); - ret = nvvar_add(d->d_name, val); + ret = __nvvar_add(d->d_name, val); if (ret) pr_err("failed to create nv variable %s: %s\n", d->d_name, strerror(-ret)); -- cgit v1.2.3 From 3fadbdae1fd5fb3d9a078f29bf2fb6f14d808c00 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 21 Jul 2016 14:37:37 +0200 Subject: nv: Save nv variables on shutdown With this patch nv variables are automatically saved whenever barebox shuts down (that is 'reset' is executed or a kernel is started). With this the additional 'saveenv' step becomes unnecessary. The nv variables are stored in the environment and the estasblished behaviour is that files in the environment must be manually saved using 'saveenv'. This behaviour shall be kept for now, so this patch cannot just call 'saveenv' since that would save the modified environment files aswell. Instead we read the environment from the device, modifiy the nv variables and save the environment back. Since this changes a long existing behaviour messages are printed the first time a nv variable is modified and during shutdown when the variables are actually saved. Signed-off-by: Sascha Hauer --- common/environment.c | 4 +++ common/globalvar.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++-- include/globalvar.h | 3 ++ 3 files changed, 85 insertions(+), 3 deletions(-) (limited to 'common') diff --git a/common/environment.c b/common/environment.c index c3ad25266a..db127d71ad 100644 --- a/common/environment.c +++ b/common/environment.c @@ -364,6 +364,10 @@ int envfs_save(const char *filename, const char *dirname, unsigned flags) ret = 0; +#ifdef CONFIG_NVVAR + if (!strcmp(filename, default_environment_path_get())) + nv_var_set_clean(); +#endif out: close(envfd); out1: diff --git a/common/globalvar.c b/common/globalvar.c index be082314e7..4110a067a3 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -9,6 +9,9 @@ #include #include #include +#include + +static int nv_dirty; struct device_d global_device = { .name = "global", @@ -20,6 +23,11 @@ struct device_d nv_device = { .id = DEVICE_ID_SINGLE, }; +void nv_var_set_clean(void) +{ + nv_dirty = 0; +} + int globalvar_add(const char *name, int (*set)(struct device_d *dev, struct param_d *p, const char *val), const char *(*get)(struct device_d *, struct param_d *p), @@ -43,16 +51,16 @@ void globalvar_remove(const char *name) dev_remove_param(param); } -static int nv_save(const char *name, const char *val) +static int __nv_save(const char *prefix, const char *name, const char *val) { int fd, ret; char *fname; - ret = make_directory("/env/nv"); + ret = make_directory(prefix); if (ret) return ret; - fname = basprintf("/env/nv/%s", name); + fname = basprintf("%s/%s", prefix, name); fd = open(fname, O_CREAT | O_WRONLY | O_TRUNC); @@ -68,6 +76,25 @@ static int nv_save(const char *name, const char *val) return 0; } +static int nv_save(const char *name, const char *val) +{ + int ret; + static int once = 1; + + ret = __nv_save("/env/nv", name, val); + if (ret) + return ret; + + if (once) { + pr_info("nv variable modified, will save nv variables on shutdown\n"); + once = 0; + } + + nv_dirty = 1; + + return 0; +} + /** * dev_param_init_from_nv - initialize a device parameter from nv variable * @dev: The device @@ -423,3 +450,51 @@ static int globalvar_init(void) pure_initcall(globalvar_init); BAREBOX_MAGICVAR_NAMED(global_version, global.version, "The barebox version"); + +/** + * nvvar_save - save NV variables to persistent environment + * + * This saves the NV variables to the persisitent environment without saving + * the other files in the environment that might be changed. + */ +int nvvar_save(void) +{ + struct param_d *param; + const char *env = default_environment_path_get(); + int ret; +#define TMPDIR "/.env.tmp" + if (!nv_dirty || !env) + return 0; + + if (IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) + defaultenv_load(TMPDIR, 0); + + envfs_load(env, TMPDIR, 0); + + list_for_each_entry(param, &nv_device.parameters, list) { + ret = __nv_save(TMPDIR "/nv", param->name, + dev_get_param(&nv_device, param->name)); + if (ret) { + pr_err("Cannot save NV var: %s\n", strerror(-ret)); + goto out; + } + } + + envfs_save(env, TMPDIR, 0); +out: + unlink_recursive(TMPDIR, NULL); + + if (!ret) + nv_dirty = 0; + + return ret; +} + +static void nv_exit(void) +{ + if (nv_dirty) + pr_info("nv variables modified, saving them\n"); + + nvvar_save(); +} +predevshutdown_exitcall(nv_exit); diff --git a/include/globalvar.h b/include/globalvar.h index 67b97de486..1cd8d21a2e 100644 --- a/include/globalvar.h +++ b/include/globalvar.h @@ -173,4 +173,7 @@ static inline void dev_param_init_from_nv(struct device_d *dev, const char *name #endif +void nv_var_set_clean(void); +int nvvar_save(void); + #endif /* __GLOBALVAR_H */ -- cgit v1.2.3 From 75926bc33d2ec53e7b81cdfd68b66725fd8cd5ac Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 19 Jul 2016 08:09:20 +0200 Subject: nv: Use dev_remove_param to delete nv variable dev_remove_param() is exactly for the purpose of removing a device parameter, so use this function instead of open coding the functionality. Signed-off-by: Sascha Hauer --- common/globalvar.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'common') diff --git a/common/globalvar.c b/common/globalvar.c index 4110a067a3..a2eaaa0223 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -304,13 +304,12 @@ int nvvar_remove(const char *name) return -ENOENT; fname = basprintf("/env/nv/%s", p->name); + + dev_remove_param(p); + unlink(fname); free(fname); - list_del(&p->list); - free(p->name); - free(p); - return 0; } -- cgit v1.2.3 From 04d6b35b5d9a9ce5583ed04e8c7b6cf37d86fed0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Mon, 25 Jul 2016 10:14:15 +0200 Subject: lib: Add Kconfig symbol for FNMATCH fnmatch is useful on its own, so make a separate Kconfig symbol and select it from GLOB. Signed-off-by: Sascha Hauer --- common/Kconfig | 1 + lib/Kconfig | 3 +++ lib/Makefile | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) (limited to 'common') diff --git a/common/Kconfig b/common/Kconfig index 6ce2a76afa..a85ee8daca 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -421,6 +421,7 @@ config MAXARGS config GLOB bool + select FNMATCH prompt "globbing support" help If you want to use wildcards like * or ? say y here. diff --git a/lib/Kconfig b/lib/Kconfig index d5f99ae2e5..f9f25bdef8 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -39,6 +39,9 @@ config BCH config BITREV bool +config FNMATCH + bool + config QSORT bool diff --git a/lib/Makefile b/lib/Makefile index 92404fd331..1be1742499 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -27,7 +27,7 @@ obj-$(CONFIG_ZLIB) += decompress_inflate.o zlib_inflate/ obj-$(CONFIG_XZ_DECOMPRESS) += decompress_unxz.o xz/ obj-$(CONFIG_CMDLINE_EDITING) += readline.o obj-$(CONFIG_SIMPLE_READLINE) += readline_simple.o -obj-$(CONFIG_GLOB) += fnmatch.o +obj-$(CONFIG_FNMATCH) += fnmatch.o obj-$(CONFIG_GENERIC_FIND_NEXT_BIT) += find_next_bit.o obj-y += glob.o obj-y += notifier.o -- cgit v1.2.3 From e844f9c60d1e13f28bdb1ed95102df1e6df44faa Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 22 Jul 2016 11:51:34 +0200 Subject: nv: Allow wildcards when removing NV vars With this patch 'nv -r' can also take "*" and "?" wildcards for nv variables. This makes it easier to remove multiple nv variables. Signed-off-by: Sascha Hauer --- common/Kconfig | 1 + common/globalvar.c | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) (limited to 'common') diff --git a/common/Kconfig b/common/Kconfig index a85ee8daca..027b8da100 100644 --- a/common/Kconfig +++ b/common/Kconfig @@ -169,6 +169,7 @@ config NVVAR default y if !SHELL_NONE depends on GLOBALVAR depends on ENV_HANDLING + select FNMATCH help Non volatile environment variables begin with "nv.". They behave like global variables above, but their values are saved in the environment diff --git a/common/globalvar.c b/common/globalvar.c index a2eaaa0223..44e6528f6c 100644 --- a/common/globalvar.c +++ b/common/globalvar.c @@ -10,6 +10,7 @@ #include #include #include +#include static int nv_dirty; @@ -293,22 +294,23 @@ int nvvar_add(const char *name, const char *value) int nvvar_remove(const char *name) { - struct param_d *p; + struct param_d *p, *tmp; char *fname; if (!IS_ENABLED(CONFIG_NVVAR)) return -ENOSYS; - p = get_param_by_name(&nv_device, name); - if (!p) - return -ENOENT; + list_for_each_entry_safe(p, tmp, &nv_device.parameters, list) { + if (fnmatch(name, p->name, 0)) + continue; - fname = basprintf("/env/nv/%s", p->name); + fname = basprintf("/env/nv/%s", p->name); - dev_remove_param(p); + dev_remove_param(p); - unlink(fname); - free(fname); + unlink(fname); + free(fname); + } return 0; } -- cgit v1.2.3