[alsa-devel] [PATCH] ASoC: topology: Fix not to keep a reference to tplg fw

Takashi Iwai tiwai at suse.de
Fri Nov 27 07:21:28 CET 2015


On Fri, 27 Nov 2015 12:42:04 +0100,
Subhransu S. Prusty wrote:
> 
> On Fri, Nov 27, 2015 at 06:54:15AM +0100, Takashi Iwai wrote:
> > On Fri, 27 Nov 2015 10:15:19 +0100,
> > Subhransu S. Prusty wrote:
> > > 
> > > On Thu, Nov 26, 2015 at 06:39:02PM +0100, Takashi Iwai wrote:
> > > > On Thu, 26 Nov 2015 17:13:43 +0100,
> > > > Vinod Koul wrote:
> > > > > 
> > > > > On Thu, Nov 26, 2015 at 12:46:24PM +0100, Takashi Iwai wrote:
> > > > > 
> > > > > > 
> > > > > > Well, for judging this, we have to follow the code more closely.  And
> > > > > > it's why I asked which path does it happen exactly.
> > > > > > 
> > > > > > There are two different paths where the snd_kcontrol_new is used: the
> > > > > > standard controls and dapm.  The former is immediately instantiated
> > > > > > via snd_soc_cnew(), so it's fine as is, no need to change.  But the
> > > > > > latter is different.
> > > > > > 
> > > > > > The latter, dapm case, always allocates the snd_kcontrol_new array in
> > > > > > kcontrol_news field.  So, we need to change in each function
> > > > > > allocating this to do kstrdump() for each kcontrol_new element, and
> > > > > > each place calling kfree() of kcontrol_news should free the string of
> > > > > > each item in return.
> > > > > 
> > > > > It is the latter dapm case with added complexity of topology core creating
> > > > > these kcontrols. I will reproduce this and send the oops tomorrow
> > > > 
> > > > Not too complex in this case because there are only a few users.
> > > > A totally untested patch is below.
> > > > 
> > > > 
> > > > Takashi
> > > > 
> > > > ---
> > > > diff --git a/sound/soc/soc-topology.c b/sound/soc/soc-topology.c
> > > > index 8d7ec80af51b..1f684975b541 100644
> > > > --- a/sound/soc/soc-topology.c
> > > > +++ b/sound/soc/soc-topology.c
> > > > @@ -427,6 +427,16 @@ static void remove_enum(struct snd_soc_component *comp,
> > > >  	kfree(se);
> > > >  }
> > > >  
> > > > +static void free_kcontrol_news(const struct snd_kcontrol_new *_wc, int nums)
> > > > +{
> > > > +	struct snd_kcontrol_new *wc = (struct snd_kcontrol_new *)_wc;
> > > > +	int i;
> > > > +
> > > > +	for (i = 0; i < nums && wc[i].name; i++)
> > > > +		kfree(wc[i].name);
> > > > +	kfree(wc);
> > > > +}
> > > > +
> > > >  /* remove a byte kcontrol */
> > > >  static void remove_bytes(struct snd_soc_component *comp,
> > > >  	struct snd_soc_dobj *dobj, int pass)
> > > > @@ -477,7 +487,7 @@ static void remove_widget(struct snd_soc_component *comp,
> > > >  			kfree(se->dobj.control.dtexts[i]);
> > > >  
> > > >  		kfree(se);
> > > > -		kfree(w->kcontrol_news);
> > > > +		free_kcontrol_news(w->kcontrol_news, 1);
> > > >  	} else {
> > > >  		/* non enumerated widget mixer */
> > > >  		for (i = 0; i < w->num_kcontrols; i++) {
> > > > @@ -490,7 +500,7 @@ static void remove_widget(struct snd_soc_component *comp,
> > > >  			snd_ctl_remove(card, w->kcontrols[i]);
> > > >  			kfree(sm);
> > > >  		}
> > > > -		kfree(w->kcontrol_news);
> > > > +		free_kcontrol_news(w->kcontrol_news, w->num_kcontrols);
> > > Hi Takashi,
> > > 
> > > I have not tested this patch yet. But it should fix the oops. Just looking
> > > the code I find remove_widget is either called from snd_soc_tplg_widget_remove
> > > or from snd_soc_tplg_component_remove. The xxx_component_remove is called
> > > during unregister of the component and there is no caller to
> > > snd_soc_tplg_widget_remove.
> > > 
> > > I guess the intention here is to free the kcontrol_news immediately after the
> > > card is registered. Please correct me if I am wrong.
> > 
> > It is already freed in the original code.  The only addition is to
> > free the newly allocated strings in kcontrol_news.  So kfree() is
> > replaced with free_kcontrol_news().
> > 
> > > Otherwise shouldn't the devm version of kstrdup work good as it just frees
> > > the memory when the device is removed?
> > 
> > No, as already mentioned, devm won't release the data until unbind and
> > the topology data might be reloaded repeatedly, thus user can hog the
> > kernel memory unlimitedly.
> Then which of the APIs snd_soc_tplg_widget_remove or
> snd_soc_tplg_component_remove should free the memory in this scenairo? I
> guess it should be snd_soc_tplg_widget_remove, but I don't see a caller of
> this API.

Then it's a driver's failure.  It needs to call it appropriately
before reloading.  Or it was supposed to be invoked from
snd_soc_tplg_component_remove()?  I don't know.


Takashi


More information about the Alsa-devel mailing list