On Fri, Jul 19, 2019 at 09:38:11AM +0200, Wolfgang Denk wrote:
> Dear AKASHI Takahiro,
> 
> In message <20190717082525.891-3-takahiro.aka...@linaro.org> you wrote:
> > The following interfaces are extended to accept an additional argument,
> > context:
> >     env_import() -> env_import_ext()
> >     env_export() -> env_export_ext()
> >     env_load() -> env_load_ext()
> >     env_save() -> env_save_ext()
> 
> Please don't such renames, see previous comments.

I didn't rename them.

> > -int env_import(const char *buf, int check)
> > +int env_import_ext(const char *buf, enum env_context ctx, int check)

env_import() is re-defined using env_import_ext() below.

> I think this needs at least additional documentation.
> 
> From the explantions so far, a context is always associated with a
> variable, i. e. it is a property of the variable.  Here it becomes
> clear that the context has an additional meaning, separate storage.

I described in my cover letter.

> It should be documented that one block of variables such as handled
> by the env import / export routines will always only process
> veriables of a specific context.

Okay, but this is not specific to this function.
I'm going to add detailed function descriptions
if you agree with these new interfaces. Do you?

> 
> > -   if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0,
> > -                   0, NULL)) {
> > +   if (himport_ext(&env_htab, ctx, (char *)ep->data, ep->data_size,
> > +                   /*
> > +                    * FIXME:
> > +                    * H_NOCLEAR is necessary here to handle
> > +                    * multiple contexts simultaneously.
> > +                    * This, however, breaks backward compatibility.
> > +                    */
> > +                   '\0', H_NOCLEAR, 0, 0, NULL)) {
> 
> This is the result of a deign bug.  You can never have "multiple
> contexts simultaneously", because the code as you designed it always
> has only one context per data block - and I can;t see how this could
> be changed, as the external storage format ('name=value\0') does not
> provide a way to include variable-specific context information.

Please read path#14 where a fat driver is modified to maintain UEFI
variables in U-Boot environment hash tables.

If UEFI variables need not be maintained in a single U-Boot environment,
my whole patch set goes in vain. (This is my "Plan B" implementation.)

> > -   set_default_env("import failed", 0);
> > +   if (ctx == ENVCTX_UBOOT)
> > +           set_default_env("import failed", 0);
> 
> Should we not also have default settings for other contexts as well?

Handling for default (initial) variables may vary context to context.
It should be implemented depending on their requirements.

> > +int env_import_redund_ext(const char *buf1, int buf1_read_fail,
> > +                     const char *buf2, int buf2_read_fail,
> > +                     enum env_context ctx)
> > +{
> > +   /* TODO */
> > +   return 0;
> 
> !!
> 
> Do you plan to implement redundant storage for UEFI data as well? It
> would make sense, wouldn't it?

Yes and no.
My current focus is to determine if my approach is acceptable or not.

> > -           pr_err("Cannot export environment: errno = %d\n", errno);
> > +           pr_err("Cannot export environment: errno = %d\n",
> > +                  errno);
> 
> Why did you change this?

Maybe a mistake?

> > -   env_out->crc = crc32(0, env_out->data, ENV_SIZE);
> > +   if (*env_out) {
> > +           envp = *env_out;
> > +   } else {
> > +           envp = malloc(sizeof(*envp) + len);
> > +           if (!envp) {
> > +                   pr_err("Out of memory\n");
> > +                   free(data);
> > +                   return 1;
> > +           }
> > +           *env_out = envp;
> > +
> > +           envp->data_size = len;
> > +           memcpy(envp->data, data, len);
> > +           free(data);
> > +   }
> 
> It seems you have a memory leak here. I cannot find a free(envp)
> anywhere.

envp will be returned to a caller via env_out.

> Speaking about memory... what is the overall code / data size impact
> of this patch set?

No statistics yet.

> 
> > --- a/env/env.c
> > +++ b/env/env.c
> > @@ -85,12 +85,12 @@ static enum env_location env_locations[] = {
> >  #endif
> >  };
> >  
> > -static bool env_has_inited(enum env_location location)
> > +static bool env_has_inited(enum env_context ctx, enum env_location 
> > location)
> >  {
> > -   return gd->env_has_init & BIT(location);
> > +   return gd->env_has_init[ctx] & BIT(location);
> >  }
> 
> This should be re-considered.  GD is a tight resource, so increasing
> it's size should be really justified.  Also, I wonder if we really
> should initialize all contexts the same.  We should keep in mind
> that many boards already need the (U-Boot) environment in SPL, but
> there resource usage is critical in most cases.

Yes, I think that I have not paid enough attentions to SPL case.
I will appreciate your suggestions.

> I think it would make a lot of sense to initialize only the U-Boot
> environment early (like in SPL), and delay this for all other
> contexts until U-Boot porper is running, where we have sufficient
> resources available.

Yeah, but see my comment below.

> 
> > -static struct env_driver *env_driver_lookup(enum env_operation op, int 
> > prio)
> > +static struct env_driver *env_driver_lookup(enum env_context ctx,
> > +                                       enum env_operation op, int prio)
> >  {
> > -   enum env_location loc = env_get_location(op, prio);
> > +   enum env_location loc;
> >     struct env_driver *drv;
> >  
> > +   if (ctx == ENVCTX_UBOOT)
> > +           loc = env_get_location(op, prio);
> > +   else
> > +           loc = env_get_location_ext(ctx, op, prio);
> 
> This makes no sense.  ENVCTX_UBOOT is just one of the available
> contexts; no "if" should be needed here.

NAK.
env_get_location is currently defined as a weak function.
So this hack is necessary, in particular, on a system where
UEFI is not enabled and env_get_location is yet overwritten.

> > -           if (!drv->load)
> > +           if ((ctx == ENVCTX_UBOOT && !drv->load) ||
> > +               (ctx != ENVCTX_UBOOT && !drv->load_ext))
> >                     continue;
> 
> Ditto here.
> 
> > -           ret = drv->load();
> > +           if (ctx == ENVCTX_UBOOT)
> > +                   ret = drv->load();
> > +           else
> > +                   ret = drv->load_ext(ctx);
> 
> ...and here.
> 
> > -   env_get_location(ENVOP_LOAD, best_prio);
> > +   if (ctx == ENVCTX_UBOOT)
> > +           env_get_location(ENVOP_LOAD, best_prio);
> > +   else
> > +           env_get_location_ext(ctx, ENVOP_LOAD, best_prio);
> 
> ...and here.
> 
> > -           if (!drv->save)
> > +           if ((ctx == ENVCTX_UBOOT && !drv->save) ||
> > +               (ctx != ENVCTX_UBOOT && !drv->save_ext))
> >                     return -ENODEV;
> 
> ...and here.
> 
> > -           if (!env_has_inited(drv->location))
> > +           if (!env_has_inited(ctx, drv->location))
> >                     return -ENODEV;
> 
> ...and here.
> 
> > -           ret = drv->save();
> > +           if (ctx == ENVCTX_UBOOT)
> > +                   ret = drv->save();
> > +           else
> > +                   ret = drv->save_ext(ctx);
> 
> ...and here.
> 
> 
> >  int env_init(void)
> >  {
> >     struct env_driver *drv;
> >     int ret = -ENOENT;
> > -   int prio;
> > +   int ctx, prio;
> 
> Error.  Context is an enum.
> 
> > +   /* other than ENVCTX_UBOOT */
> > +   for (ctx = 1;  ctx < ENVCTX_COUNT; ctx++) {
> 
> Ugly code.  "ctx" is an enum, so "1" is a magic number here that
> should not be used.

There are already bunch of code where enum is interchangeably
used as an integer.

> Please fix.
> 
> > -   for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
> > +   /* ENVCTX_UBOOT */
> > +   ret = -ENOENT;
> > +   for (prio = 0; (drv = env_driver_lookup(ENVCTX_UBOOT, ENVOP_INIT,
> > +                                           prio));
> > +        prio++) {
> 
> See problem above. U-Boot context should not need separate code, it
> is just one context among others...

It seems to me that this comment is conflicting with your assertion
below.

> ...unless you really split initialization into early init (U-Boot,
> eventually already in SPL) and late init (all other contexts,
> delayed until U-Boot proper).
> 
> > --- a/include/asm-generic/global_data.h
> > +++ b/include/asm-generic/global_data.h
> > @@ -20,6 +20,7 @@
> >   */
> >  
> >  #ifndef __ASSEMBLY__
> > +#include <environment.h>
> >  #include <fdtdec.h>
> >  #include <membuff.h>
> >  #include <linux/list.h>
> > @@ -50,8 +51,10 @@ typedef struct global_data {
> >  #endif
> >     unsigned long env_addr;         /* Address  of Environment struct */
> >     unsigned long env_valid;        /* Environment valid? enum env_valid */
> > -   unsigned long env_has_init;     /* Bitmask of boolean of struct 
> > env_location offsets */
> > -   int env_load_prio;              /* Priority of the loaded environment */
> > +   unsigned long env_has_init[ENVCTX_COUNT_MAX];
> > +                   /* Bitmask of boolean of struct env_location offsets */
> > +   int env_load_prio[ENVCTX_COUNT_MAX];
> > +                                   /* Priority of the loaded environment */
> 
> NAK.  Please keep this information out of GD.  This is a tight
> resource, we must not extend it for such purposes.

But in this way, we will have to handle contexts differently
depending on whether it is ENVCTX_UBOOT or not.


> > --- a/include/env_default.h
> > +++ b/include/env_default.h
> > @@ -15,6 +15,7 @@ env_t environment __UBOOT_ENV_SECTION__(environment) = {
> >  #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
> >     1,              /* Flags: valid */
> >  #endif
> > +   ENV_SIZE,
> 
> Full NAK!!!
> 
> You *MUST NOT* change the data structure of the environment on
> external storage, as this breaks compatibility with all existing
> systems.  This is a strict no-go.

Let me think, but I don't have a good idea yet.

> > diff --git a/include/environment.h b/include/environment.h
> > index cd966761416e..9fa085a9b728 100644
> > --- a/include/environment.h
> > +++ b/include/environment.h
> > @@ -134,21 +134,31 @@ extern unsigned long nand_env_oob_offset;
> >  #include "compiler.h"
> >  
> >  #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
> > -# define ENV_HEADER_SIZE   (sizeof(uint32_t) + 1)
> > -
> >  # define ACTIVE_FLAG   1
> >  # define OBSOLETE_FLAG 0
> > +
> > +#define ENVIRONMENT_HEADER \
> > +   uint32_t        crc;            /* CRC32 over data bytes        */ \
> > +   uint32_t        data_size;      /* Environment data size        */ \
> > +   unsigned char   flags;          /* active/obsolete flags        */
> >  #else
> > -# define ENV_HEADER_SIZE   (sizeof(uint32_t))
> > +#define ENVIRONMENT_HEADER \
> > +   uint32_t        crc;            /* CRC32 over data bytes        */ \
> > +   uint32_t        data_size;      /* Environment data size        */
> >  #endif
> >  
> > +typedef struct environment_hdr {
> > +   ENVIRONMENT_HEADER
> > +   unsigned char   data[];         /* Environment data             */
> > +} env_hdr_t;
> > +
> > +# define ENV_HEADER_SIZE   (sizeof(env_hdr_t))
> > +
> > +/* For compatibility */
> >  #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
> >  
> >  typedef struct environment_s {
> > -   uint32_t        crc;            /* CRC32 over data bytes        */
> > -#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
> > -   unsigned char   flags;          /* active/obsolete flags        */
> > -#endif
> > +   ENVIRONMENT_HEADER
> >     unsigned char   data[ENV_SIZE]; /* Environment data             */
> >  } env_t;
> 
> Full NAK!!!
> 
> You *MUST NOT* change the data structure of the environment on
> external storage, as this breaks compatibility with all existing
> systems.  This is a strict no-go.
> 
> >      */
> >     int (*load)(void);
> >  
> > +   /**
> > +    * load_ext() - Load given environment context from storage
> > +    *
> > +    * This method is optional. If not provided, no environment will be
> > +    * loaded.
> > +    *
> > +    * @ctx:        context to be loaded
> > +    * Return:      0 if OK, -ve on error
> > +    */
> > +   int (*load_ext)(enum env_context ctx);
> > +
> >     /**
> >      * save() - Save the environment to storage
> >      *
> > @@ -225,6 +251,16 @@ struct env_driver {
> >      */
> >     int (*save)(void);
> >  
> > +   /**
> > +    * save_ext() - Save given environment context to storage
> > +    *
> > +    * This method is required for 'saveenv' to work.
> > +    *
> > +    * @ctx:        context to be saved
> > +    * Return:      0 if OK, -ve on error
> > +    */
> > +   int (*save_ext)(enum env_context ctx);
> > +
> >     /**
> >      * init() - Set up the initial pre-relocation environment
> >      *
> > @@ -234,6 +270,17 @@ struct env_driver {
> >      * other -ve on error
> >      */
> >     int (*init)(void);
> > +
> > +   /**
> > +    * init() - Set up the initial pre-relocation environment
> > +    *
> > +    * This method is optional.
> > +    *
> > +    * @ctx:        context to be saved
> > +    * @return 0 if OK, -ENOENT if no initial environment could be found,
> > +    * other -ve on error
> > +    */
> > +   int (*init_ext)(enum env_context ctx);
> 
> NAK.  We should ot need always pairs of functions foo() and
> foo_ext().  There should always be only foo(), which supports
> contexts.

This is a transition state as I mentioned in "known issues/TODOs"
in my cover letter.
If you agree, I can remove all the existing interfaces
but only when all the storage drivers are converted.

Thanks,
-Takahiro Akashi

> >  /* Import from binary representation into hash table */
> >  int env_import(const char *buf, int check);
> > +int env_import_ext(const char *buf, enum env_context ctx, int check);
> >  
> >  /* Export from hash table into binary representation */
> >  int env_export(env_t *env_out);
> > +int env_export_ext(env_hdr_t **env_out, enum env_context ctx);
> >  
> >  #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
> >  /* Select and import one of two redundant environments */
> >  int env_import_redund(const char *buf1, int buf1_status,
> >                   const char *buf2, int buf2_status);
> > +int env_import_redund_ext(const char *buf1, int buf1_status,
> > +                     const char *buf2, int buf2_status,
> > +                     enum env_context ctx);
> >  #endif
> 
> Ditto here and following.
> 
> Best regards,
> 
> Wolfgang Denk
> 
> -- 
> DENX Software Engineering GmbH,      Managing Director: Wolfgang Denk
> HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany
> Phone: (+49)-8142-66989-10 Fax: (+49)-8142-66989-80 Email: w...@denx.de
> panic: kernel trap (ignored)
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to