aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorJulia Lawall <julia@diku.dk>2010-08-31 11:48:55 -0400
committerKumar Gala <galak@kernel.crashing.org>2011-03-15 14:48:16 -0400
commit48a10cdfc0262ee7b5ccd4cbb673957e320ec563 (patch)
tree0b329e6f0d40b997c74c32531a425c9f4906d18d /drivers/tty
parentafc0a07d4a283599ac3a6a31d7454e9baaeccca0 (diff)
drivers/serial/ucc_uart.c: Add of_node_put to avoid memory leak
Add a call to of_node_put in the error handling code following a call to of_find_compatible_node or of_find_node_by_type. This patch also substantially reorganizes the error handling code in the function, to that it is possible first to jump to code that frees qe_port and then to jump to code that also puts np. The semantic match that finds this problem is as follows: (http://coccinelle.lip6.fr/) // <smpl> @r exists@ local idexpression x; expression E,E1,E2; statement S; @@ *x = (of_find_node_by_path |of_find_node_by_name |of_find_node_by_phandle |of_get_parent |of_get_next_parent |of_get_next_child |of_find_compatible_node |of_match_node |of_find_node_by_type |of_find_node_with_property |of_find_matching_node |of_parse_phandle )(...); ... if (x == NULL) S <... when != x = E *if (...) { ... when != of_node_put(x) when != if (...) { ... of_node_put(x); ... } ( return <+...x...+>; | * return ...; ) } ...> ( E2 = x; | of_node_put(x); ) // </smpl> Signed-off-by: Julia Lawall <julia@diku.dk> Acked-by: Timur Tabi <timur@freescale.com> Acked-by: Grant Likely <grant.likely@secretlab.ca> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/ucc_uart.c67
1 files changed, 35 insertions, 32 deletions
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index 3f4848e2174a..38a5ef0ae394 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1270,13 +1270,12 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1270 ret = of_address_to_resource(np, 0, &res); 1270 ret = of_address_to_resource(np, 0, &res);
1271 if (ret) { 1271 if (ret) {
1272 dev_err(&ofdev->dev, "missing 'reg' property in device tree\n"); 1272 dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
1273 kfree(qe_port); 1273 goto out_free;
1274 return ret;
1275 } 1274 }
1276 if (!res.start) { 1275 if (!res.start) {
1277 dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n"); 1276 dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
1278 kfree(qe_port); 1277 ret = -EINVAL;
1279 return -EINVAL; 1278 goto out_free;
1280 } 1279 }
1281 qe_port->port.mapbase = res.start; 1280 qe_port->port.mapbase = res.start;
1282 1281
@@ -1286,17 +1285,17 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1286 if (!iprop) { 1285 if (!iprop) {
1287 iprop = of_get_property(np, "device-id", NULL); 1286 iprop = of_get_property(np, "device-id", NULL);
1288 if (!iprop) { 1287 if (!iprop) {
1289 kfree(qe_port);
1290 dev_err(&ofdev->dev, "UCC is unspecified in " 1288 dev_err(&ofdev->dev, "UCC is unspecified in "
1291 "device tree\n"); 1289 "device tree\n");
1292 return -EINVAL; 1290 ret = -EINVAL;
1291 goto out_free;
1293 } 1292 }
1294 } 1293 }
1295 1294
1296 if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) { 1295 if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
1297 dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop); 1296 dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
1298 kfree(qe_port); 1297 ret = -ENODEV;
1299 return -ENODEV; 1298 goto out_free;
1300 } 1299 }
1301 qe_port->ucc_num = *iprop - 1; 1300 qe_port->ucc_num = *iprop - 1;
1302 1301
@@ -1310,16 +1309,16 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1310 sprop = of_get_property(np, "rx-clock-name", NULL); 1309 sprop = of_get_property(np, "rx-clock-name", NULL);
1311 if (!sprop) { 1310 if (!sprop) {
1312 dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n"); 1311 dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
1313 kfree(qe_port); 1312 ret = -ENODEV;
1314 return -ENODEV; 1313 goto out_free;
1315 } 1314 }
1316 1315
1317 qe_port->us_info.rx_clock = qe_clock_source(sprop); 1316 qe_port->us_info.rx_clock = qe_clock_source(sprop);
1318 if ((qe_port->us_info.rx_clock < QE_BRG1) || 1317 if ((qe_port->us_info.rx_clock < QE_BRG1) ||
1319 (qe_port->us_info.rx_clock > QE_BRG16)) { 1318 (qe_port->us_info.rx_clock > QE_BRG16)) {
1320 dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n"); 1319 dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
1321 kfree(qe_port); 1320 ret = -ENODEV;
1322 return -ENODEV; 1321 goto out_free;
1323 } 1322 }
1324 1323
1325#ifdef LOOPBACK 1324#ifdef LOOPBACK
@@ -1329,39 +1328,39 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1329 sprop = of_get_property(np, "tx-clock-name", NULL); 1328 sprop = of_get_property(np, "tx-clock-name", NULL);
1330 if (!sprop) { 1329 if (!sprop) {
1331 dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n"); 1330 dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
1332 kfree(qe_port); 1331 ret = -ENODEV;
1333 return -ENODEV; 1332 goto out_free;
1334 } 1333 }
1335 qe_port->us_info.tx_clock = qe_clock_source(sprop); 1334 qe_port->us_info.tx_clock = qe_clock_source(sprop);
1336#endif 1335#endif
1337 if ((qe_port->us_info.tx_clock < QE_BRG1) || 1336 if ((qe_port->us_info.tx_clock < QE_BRG1) ||
1338 (qe_port->us_info.tx_clock > QE_BRG16)) { 1337 (qe_port->us_info.tx_clock > QE_BRG16)) {
1339 dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n"); 1338 dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
1340 kfree(qe_port); 1339 ret = -ENODEV;
1341 return -ENODEV; 1340 goto out_free;
1342 } 1341 }
1343 1342
1344 /* Get the port number, numbered 0-3 */ 1343 /* Get the port number, numbered 0-3 */
1345 iprop = of_get_property(np, "port-number", NULL); 1344 iprop = of_get_property(np, "port-number", NULL);
1346 if (!iprop) { 1345 if (!iprop) {
1347 dev_err(&ofdev->dev, "missing port-number in device tree\n"); 1346 dev_err(&ofdev->dev, "missing port-number in device tree\n");
1348 kfree(qe_port); 1347 ret = -EINVAL;
1349 return -EINVAL; 1348 goto out_free;
1350 } 1349 }
1351 qe_port->port.line = *iprop; 1350 qe_port->port.line = *iprop;
1352 if (qe_port->port.line >= UCC_MAX_UART) { 1351 if (qe_port->port.line >= UCC_MAX_UART) {
1353 dev_err(&ofdev->dev, "port-number must be 0-%u\n", 1352 dev_err(&ofdev->dev, "port-number must be 0-%u\n",
1354 UCC_MAX_UART - 1); 1353 UCC_MAX_UART - 1);
1355 kfree(qe_port); 1354 ret = -EINVAL;
1356 return -EINVAL; 1355 goto out_free;
1357 } 1356 }
1358 1357
1359 qe_port->port.irq = irq_of_parse_and_map(np, 0); 1358 qe_port->port.irq = irq_of_parse_and_map(np, 0);
1360 if (qe_port->port.irq == NO_IRQ) { 1359 if (qe_port->port.irq == NO_IRQ) {
1361 dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n", 1360 dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
1362 qe_port->ucc_num + 1); 1361 qe_port->ucc_num + 1);
1363 kfree(qe_port); 1362 ret = -EINVAL;
1364 return -EINVAL; 1363 goto out_free;
1365 } 1364 }
1366 1365
1367 /* 1366 /*
@@ -1373,8 +1372,8 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1373 np = of_find_node_by_type(NULL, "qe"); 1372 np = of_find_node_by_type(NULL, "qe");
1374 if (!np) { 1373 if (!np) {
1375 dev_err(&ofdev->dev, "could not find 'qe' node\n"); 1374 dev_err(&ofdev->dev, "could not find 'qe' node\n");
1376 kfree(qe_port); 1375 ret = -EINVAL;
1377 return -EINVAL; 1376 goto out_free;
1378 } 1377 }
1379 } 1378 }
1380 1379
@@ -1382,8 +1381,8 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1382 if (!iprop) { 1381 if (!iprop) {
1383 dev_err(&ofdev->dev, 1382 dev_err(&ofdev->dev,
1384 "missing brg-frequency in device tree\n"); 1383 "missing brg-frequency in device tree\n");
1385 kfree(qe_port); 1384 ret = -EINVAL;
1386 return -EINVAL; 1385 goto out_np;
1387 } 1386 }
1388 1387
1389 if (*iprop) 1388 if (*iprop)
@@ -1398,16 +1397,16 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1398 if (!iprop) { 1397 if (!iprop) {
1399 dev_err(&ofdev->dev, 1398 dev_err(&ofdev->dev,
1400 "missing QE bus-frequency in device tree\n"); 1399 "missing QE bus-frequency in device tree\n");
1401 kfree(qe_port); 1400 ret = -EINVAL;
1402 return -EINVAL; 1401 goto out_np;
1403 } 1402 }
1404 if (*iprop) 1403 if (*iprop)
1405 qe_port->port.uartclk = *iprop / 2; 1404 qe_port->port.uartclk = *iprop / 2;
1406 else { 1405 else {
1407 dev_err(&ofdev->dev, 1406 dev_err(&ofdev->dev,
1408 "invalid QE bus-frequency in device tree\n"); 1407 "invalid QE bus-frequency in device tree\n");
1409 kfree(qe_port); 1408 ret = -EINVAL;
1410 return -EINVAL; 1409 goto out_np;
1411 } 1410 }
1412 } 1411 }
1413 1412
@@ -1445,8 +1444,7 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1445 if (ret) { 1444 if (ret) {
1446 dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n", 1445 dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
1447 qe_port->port.line); 1446 qe_port->port.line);
1448 kfree(qe_port); 1447 goto out_np;
1449 return ret;
1450 } 1448 }
1451 1449
1452 dev_set_drvdata(&ofdev->dev, qe_port); 1450 dev_set_drvdata(&ofdev->dev, qe_port);
@@ -1460,6 +1458,11 @@ static int ucc_uart_probe(struct platform_device *ofdev,
1460 SERIAL_QE_MINOR + qe_port->port.line); 1458 SERIAL_QE_MINOR + qe_port->port.line);
1461 1459
1462 return 0; 1460 return 0;
1461out_np:
1462 of_node_put(np);
1463out_free:
1464 kfree(qe_port);
1465 return ret;
1463} 1466}
1464 1467
1465static int ucc_uart_remove(struct platform_device *ofdev) 1468static int ucc_uart_remove(struct platform_device *ofdev)