> > > static ssize_t userdatum_value_store(struct config_item *item, const
> > > char *buf,
> > > @@ -937,7 +953,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 = update_userdata(nt);
> > > + if (ret < 0)
> > > + goto out_unlock;
> > > ret = count;
> > > out_unlock:
> > > mutex_unlock(&dynamic_netconsole_mutex);
> > > @@ -1193,7 +1211,10 @@ static struct configfs_attribute
> > > *netconsole_target_attrs[] = {
> > >
> > > static void netconsole_target_release(struct config_item *item)
> > > {
> > > - kfree(to_target(item));
> > > + struct netconsole_target *nt = to_target(item);
> >
> > Thinking about this now, I suppose netconsole might be reading this in
> > parallel, and then we are freeing userdata mid-air.
> >
> > Don't we need the target_list_lock in here ?
>
> This method is called after drop_netconsole_target(), which removes
> the target from target_list. This guarantees that we won't race with
> write_ext_msg().
> Also, a config_group cannot be removed while it still has child items.
> This guarantees that we won't race with userdata or attribute
> operations.
> So I believe this is safe.
Thanks for checking it!
--breno