aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2013-12-12 18:59:08 -0500
committerDan Williams <dan.j.williams@intel.com>2013-12-13 01:48:53 -0500
commit0be8253fa2b4385e6246387db1d6067366e987ba (patch)
treee798be82ec569d306f4eae19a4c87544b30fb3b8
parentd16695a75019ac4baad7a117dc86d1d292e09115 (diff)
dmaengine: mv_xor: fix oops when channels fail to initialise
When a channel fails to initialise, we error out and clean up any previously unregistered channels by walking the entire xordev->channels array. Unfortunately, there are paths which end up storing an error pointer in this array, which we then try and dereference in the cleanup code, which causes an oops. Fix this by avoiding writing invalid pointers to this array in the first place. Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
-rw-r--r--drivers/dma/mv_xor.c24
1 files changed, 13 insertions, 11 deletions
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 79620887d637..53fb0c8365b0 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -1199,6 +1199,7 @@ static int mv_xor_probe(struct platform_device *pdev)
1199 int i = 0; 1199 int i = 0;
1200 1200
1201 for_each_child_of_node(pdev->dev.of_node, np) { 1201 for_each_child_of_node(pdev->dev.of_node, np) {
1202 struct mv_xor_chan *chan;
1202 dma_cap_mask_t cap_mask; 1203 dma_cap_mask_t cap_mask;
1203 int irq; 1204 int irq;
1204 1205
@@ -1216,21 +1217,21 @@ static int mv_xor_probe(struct platform_device *pdev)
1216 goto err_channel_add; 1217 goto err_channel_add;
1217 } 1218 }
1218 1219
1219 xordev->channels[i] = 1220 chan = mv_xor_channel_add(xordev, pdev, i,
1220 mv_xor_channel_add(xordev, pdev, i, 1221 cap_mask, irq);
1221 cap_mask, irq); 1222 if (IS_ERR(chan)) {
1222 if (IS_ERR(xordev->channels[i])) { 1223 ret = PTR_ERR(chan);
1223 ret = PTR_ERR(xordev->channels[i]);
1224 xordev->channels[i] = NULL;
1225 irq_dispose_mapping(irq); 1224 irq_dispose_mapping(irq);
1226 goto err_channel_add; 1225 goto err_channel_add;
1227 } 1226 }
1228 1227
1228 xordev->channels[i] = chan;
1229 i++; 1229 i++;
1230 } 1230 }
1231 } else if (pdata && pdata->channels) { 1231 } else if (pdata && pdata->channels) {
1232 for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) { 1232 for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) {
1233 struct mv_xor_channel_data *cd; 1233 struct mv_xor_channel_data *cd;
1234 struct mv_xor_chan *chan;
1234 int irq; 1235 int irq;
1235 1236
1236 cd = &pdata->channels[i]; 1237 cd = &pdata->channels[i];
@@ -1245,13 +1246,14 @@ static int mv_xor_probe(struct platform_device *pdev)
1245 goto err_channel_add; 1246 goto err_channel_add;
1246 } 1247 }
1247 1248
1248 xordev->channels[i] = 1249 chan = mv_xor_channel_add(xordev, pdev, i,
1249 mv_xor_channel_add(xordev, pdev, i, 1250 cd->cap_mask, irq);
1250 cd->cap_mask, irq); 1251 if (IS_ERR(chan)) {
1251 if (IS_ERR(xordev->channels[i])) { 1252 ret = PTR_ERR(chan);
1252 ret = PTR_ERR(xordev->channels[i]);
1253 goto err_channel_add; 1253 goto err_channel_add;
1254 } 1254 }
1255
1256 xordev->channels[i] = chan;
1255 } 1257 }
1256 } 1258 }
1257 1259