From 70c7b0cd7fc3a90366dfc46d8712f5da71d66b59 Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Fri, 24 Aug 2018 14:50:24 +0800 Subject: [PATCH 1/2] ASoC:topology:fix the oops bug at topology free stage. 1. because the snd_soc_dapm_route{} is allocated in stack, which cause oops during topology free stage. allocated in the heap instead of allocated in stack by changing its definition in snd_sof_route{} can avoid oops in free stage. 2. the string name is allocated in topology's short life buffer, which cause oops during topology free stage. allocated the string buffer with devm_kstrdup() can avoid oops in free stage. Signed-off-by: Wu Zhigang Suggested-by: Keyon Jie --- sound/soc/sof/pm.c | 6 +++--- sound/soc/sof/sof-priv.h | 2 +- sound/soc/sof/topology.c | 19 +++++++++++++++++-- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/sound/soc/sof/pm.c b/sound/soc/sof/pm.c index 75c1a71feb7981..ddc8c2d54bc5c9 100644 --- a/sound/soc/sof/pm.c +++ b/sound/soc/sof/pm.c @@ -85,10 +85,10 @@ static int sof_restore_pipelines(struct snd_sof_dev *sdev) if (ret < 0) { dev_err(sdev->dev, "error: failed to load route sink %s control %s source %s\n", - sroute->route->sink, - sroute->route->control ? sroute->route->control + sroute->route.sink, + sroute->route.control ? sroute->route.control : "none", - sroute->route->source); + sroute->route.source); return ret; } diff --git a/sound/soc/sof/sof-priv.h b/sound/soc/sof/sof-priv.h index d9d62461c06d22..c3431c209e35a2 100644 --- a/sound/soc/sof/sof-priv.h +++ b/sound/soc/sof/sof-priv.h @@ -267,7 +267,7 @@ struct snd_sof_widget { struct snd_sof_route { struct snd_sof_dev *sdev; - struct snd_soc_dapm_route *route; + struct snd_soc_dapm_route route; struct list_head list; /* list in sdev route list */ void *private; diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index e5e6399b3987f0..83bc90c5ea2fbd 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1999,7 +1999,22 @@ static int sof_route_load(struct snd_soc_component *scomp, int index, goto err; } - sroute->route = route; + sroute->route.source = kstrdup(route->source, GFP_KERNEL); + if (!sroute->route.source) + goto err; + + sroute->route.sink = kstrdup(route->sink, GFP_KERNEL); + if (!sroute->route.sink) { + kfree(sroute->route.source); + goto err; + } + + sroute->route.control = kstrdup(route->control, GFP_KERNEL); + if (!sroute->route.control) { + kfree(sroute->route.source); + kfree(sroute->route.sink); + goto err; + } sroute->private = connect; /* add route to route list */ @@ -2175,7 +2190,7 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) list_for_each_entry_safe(sroute, temp, &sdev->route_list, list) { /* delete dapm route */ - snd_soc_dapm_del_routes(dapm, sroute->route, 1); + snd_soc_dapm_del_routes(dapm, &sroute->route, 1); /* free sroute and its private data */ kfree(sroute->private); From 5baad2e7d63b4ff25a532c56ab856a9463f85c61 Mon Sep 17 00:00:00 2001 From: Wu Zhigang Date: Fri, 24 Aug 2018 17:20:00 +0800 Subject: [PATCH 2/2] ASoC:topology:add the remove function to free route. add the remove function to free route in sof level. Signed-off-by: Wu Zhigang --- sound/soc/sof/topology.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/sound/soc/sof/topology.c b/sound/soc/sof/topology.c index 83bc90c5ea2fbd..1c810108181950 100644 --- a/sound/soc/sof/topology.c +++ b/sound/soc/sof/topology.c @@ -1890,6 +1890,17 @@ static int spcm_bind(struct snd_soc_component *scomp, struct snd_sof_pcm *spcm, return 0; } +/* Used for free route in topology free stage */ +static void sof_route_remove(struct snd_soc_dapm_route *route) +{ + if (!route) + return; + + kfree(route->source); + kfree(route->sink); + kfree(route->control); +} + /* DAI link - used for any driver specific init */ static int sof_route_load(struct snd_soc_component *scomp, int index, struct snd_soc_dapm_route *route) @@ -2192,6 +2203,8 @@ void snd_sof_free_topology(struct snd_sof_dev *sdev) /* delete dapm route */ snd_soc_dapm_del_routes(dapm, &sroute->route, 1); + sof_route_remove(&sroute->route); + /* free sroute and its private data */ kfree(sroute->private); kfree(sroute);