Hello Jakub,

On Mon, Nov 18, 2024 at 06:33:36PM -0800, Jakub Kicinski wrote:
> Sorry for the late review, I think this will miss v6.13 :(

That is fine, there is no rush for this change.

> On Wed, 13 Nov 2024 07:10:53 -0800 Breno Leitao wrote:
> >  /**
> >   * struct netconsole_target - Represents a configured netconsole target.
> >   * @list:  Links this target into the target_list.
> > @@ -97,6 +105,7 @@ static struct console netconsole_ext;
> >   * @userdata_group:        Links to the userdata configfs hierarchy
> >   * @userdata_complete:     Cached, formatted string of append
> >   * @userdata_length:       String length of userdata_complete
> > + * @userdata_auto: Kernel auto-populated bitwise fields in userdata.
> >   * @enabled:       On / off knob to enable / disable target.
> >   *         Visible from userspace (read-write).
> >   *         We maintain a strict 1:1 correspondence between this and
> > @@ -123,6 +132,7 @@ struct netconsole_target {
> >     struct config_group     userdata_group;
> >     char userdata_complete[MAX_USERDATA_ENTRY_LENGTH * MAX_USERDATA_ITEMS];
> >     size_t                  userdata_length;
> > +   enum userdata_auto      userdata_auto;
> 
> If you want to set multiple bits here type should probably be unsigned
> long. Otherwise the enum will contain combination of its values, which
> are in themselves not valid enum values ... if that makes sense.

Yes, it does make sense. I had the feeling that something was off as
well, but I was unclear if using something different than `enum
userdata_auto` would be better. I will change to `unsigned long`
> 
> >  #endif
> >     bool                    enabled;
> >     bool                    extended;
> 
> > +   /* Check if CPU NR should be populated, and append it to the user
> > +    * dictionary.
> > +    */
> > +   if (child_count < MAX_USERDATA_ITEMS && nt->userdata_auto & AUTO_CPU_NR)
> > +           scnprintf(&nt->userdata_complete[complete_idx],
> > +                     MAX_USERDATA_ENTRY_LENGTH, " cpu=%u\n",
> > +                     raw_smp_processor_id());
> 
> I guess it may be tricky for backward compat, but shouldn't we return
> an error rather than silently skip?

yes, this should be easy to do, in fact. Probably return -E2BIG to
userspace when trying to update the entry. I thought about something as
the following patch, and piggy-back into it.

   Author: Breno Leitao <[email protected]>
   Date:   Tue Nov 19 04:32:56 2024 -0800
   
       netconsole: Enforce userdata entry limit
   
       Currently, attempting to add more than MAX_USERDATA_ITEMS to the userdata
       dictionary silently fails. This patch modifies the code to return -E2BIG
       when the number of elements exceeds the preallocated limit, providing 
clear
       feedback to userspace about the failure.
   
       Suggested-by: Jakub Kicinski <[email protected]>
       Signed-off-by: Breno Leitao <[email protected]>
   
   diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
   index 4ea44a2f48f7b..41cff8c8e8f42 100644
   --- a/drivers/net/netconsole.c
   +++ b/drivers/net/netconsole.c
   @@ -692,10 +692,11 @@ static ssize_t userdatum_value_show(struct config_item 
*item, char *buf)
        return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0]));
    }
   
   -static void update_userdata(struct netconsole_target *nt)
   +static int update_userdata(struct netconsole_target *nt)
    {
        int complete_idx = 0, child_count = 0;
        struct list_head *entry;
   +    int ret = 0;
   
        /* Clear the current string in case the last userdatum was deleted */
        nt->userdata_length = 0;
   @@ -705,8 +706,10 @@ static void update_userdata(struct netconsole_target 
*nt)
                struct userdatum *udm_item;
                struct config_item *item;
   
   -            if (child_count >= MAX_USERDATA_ITEMS)
   +            if (child_count >= MAX_USERDATA_ITEMS) {
   +                    ret = -E2BIG;
                        break;
   +            }
                child_count++;
   
                item = container_of(entry, struct config_item, ci_entry);
   @@ -726,6 +729,7 @@ static void update_userdata(struct netconsole_target *nt)
        }
        nt->userdata_length = strnlen(nt->userdata_complete,
                                      sizeof(nt->userdata_complete));
   +    return ret;
    }
   
    static ssize_t userdatum_value_store(struct config_item *item, const char 
*buf,
   @@ -748,8 +752,9 @@ static ssize_t userdatum_value_store(struct config_item 
*item, const char *buf,
   
        ud = to_userdata(item->ci_parent);
        nt = userdata_to_target(ud);
   -    update_userdata(nt);
   -    ret = count;
   +    ret = update_userdata(nt);
   +    if (!ret)
   +            ret = count;
    out_unlock:
        mutex_unlock(&dynamic_netconsole_mutex);
        return ret;
   

> 
> >     nt->userdata_length = strnlen(nt->userdata_complete,
> >                                   sizeof(nt->userdata_complete));
> >  }
> > @@ -757,7 +788,36 @@ static ssize_t userdatum_value_store(struct 
> > config_item *item, const char *buf,
> >     return ret;
> >  }
> >  
> > +static ssize_t populate_cpu_nr_store(struct config_item *item, const char 
> > *buf,
> > +                                size_t count)
> > +{
> > +   struct netconsole_target *nt = to_target(item->ci_parent);
> > +   bool cpu_nr_enabled;
> > +   ssize_t ret;
> > +
> > +   if (!nt)
> > +           return -EINVAL;
> 
> Can this happen? Only if function gets called with a NULL @item
> which would be pretty nutty.

Probably not. It is just me being chicken here. I will remove it for the
next version.

Thanks for the review,
--breno

Reply via email to