Skip to content

Commit 25c0b47

Browse files
ISCAS-VulabWim Van Sebroeck
authored andcommitted
watchdog: wdat_wdt: Fix ACPI table leak in probe function
wdat_wdt_probe() calls acpi_get_table() to obtain the WDAT ACPI table but never calls acpi_put_table() on any paths. This causes a permanent ACPI table memory leak. Add a single cleanup path which calls acpi_put_table() to ensure the ACPI table is always released. Fixes: 058dfc7 ("ACPI / watchdog: Add support for WDAT hardware watchdog") Suggested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Haotian Zhang <vulab@iscas.ac.cn> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@linux-watchdog.org>
1 parent e0c50cd commit 25c0b47

1 file changed

Lines changed: 43 additions & 21 deletions

File tree

drivers/watchdog/wdat_wdt.c

Lines changed: 43 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -326,19 +326,27 @@ static int wdat_wdt_probe(struct platform_device *pdev)
326326
return -ENODEV;
327327

328328
wdat = devm_kzalloc(dev, sizeof(*wdat), GFP_KERNEL);
329-
if (!wdat)
330-
return -ENOMEM;
329+
if (!wdat) {
330+
ret = -ENOMEM;
331+
goto out_put_table;
332+
}
331333

332334
regs = devm_kcalloc(dev, pdev->num_resources, sizeof(*regs),
333335
GFP_KERNEL);
334-
if (!regs)
335-
return -ENOMEM;
336+
if (!regs) {
337+
ret = -ENOMEM;
338+
goto out_put_table;
339+
}
336340

337341
/* WDAT specification wants to have >= 1ms period */
338-
if (tbl->timer_period < 1)
339-
return -EINVAL;
340-
if (tbl->min_count > tbl->max_count)
341-
return -EINVAL;
342+
if (tbl->timer_period < 1) {
343+
ret = -EINVAL;
344+
goto out_put_table;
345+
}
346+
if (tbl->min_count > tbl->max_count) {
347+
ret = -EINVAL;
348+
goto out_put_table;
349+
}
342350

343351
wdat->period = tbl->timer_period;
344352
wdat->wdd.min_timeout = DIV_ROUND_UP(wdat->period * tbl->min_count, 1000);
@@ -355,15 +363,20 @@ static int wdat_wdt_probe(struct platform_device *pdev)
355363
res = &pdev->resource[i];
356364
if (resource_type(res) == IORESOURCE_MEM) {
357365
reg = devm_ioremap_resource(dev, res);
358-
if (IS_ERR(reg))
359-
return PTR_ERR(reg);
366+
if (IS_ERR(reg)) {
367+
ret = PTR_ERR(reg);
368+
goto out_put_table;
369+
}
360370
} else if (resource_type(res) == IORESOURCE_IO) {
361371
reg = devm_ioport_map(dev, res->start, 1);
362-
if (!reg)
363-
return -ENOMEM;
372+
if (!reg) {
373+
ret = -ENOMEM;
374+
goto out_put_table;
375+
}
364376
} else {
365377
dev_err(dev, "Unsupported resource\n");
366-
return -EINVAL;
378+
ret = -EINVAL;
379+
goto out_put_table;
367380
}
368381

369382
regs[i] = reg;
@@ -385,8 +398,10 @@ static int wdat_wdt_probe(struct platform_device *pdev)
385398
}
386399

387400
instr = devm_kzalloc(dev, sizeof(*instr), GFP_KERNEL);
388-
if (!instr)
389-
return -ENOMEM;
401+
if (!instr) {
402+
ret = -ENOMEM;
403+
goto out_put_table;
404+
}
390405

391406
INIT_LIST_HEAD(&instr->node);
392407
instr->entry = entries[i];
@@ -417,16 +432,19 @@ static int wdat_wdt_probe(struct platform_device *pdev)
417432

418433
if (!instr->reg) {
419434
dev_err(dev, "I/O resource not found\n");
420-
return -EINVAL;
435+
ret = -EINVAL;
436+
goto out_put_table;
421437
}
422438

423439
instructions = wdat->instructions[action];
424440
if (!instructions) {
425441
instructions = devm_kzalloc(dev,
426442
sizeof(*instructions),
427443
GFP_KERNEL);
428-
if (!instructions)
429-
return -ENOMEM;
444+
if (!instructions) {
445+
ret = -ENOMEM;
446+
goto out_put_table;
447+
}
430448

431449
INIT_LIST_HEAD(instructions);
432450
wdat->instructions[action] = instructions;
@@ -443,7 +461,7 @@ static int wdat_wdt_probe(struct platform_device *pdev)
443461

444462
ret = wdat_wdt_enable_reboot(wdat);
445463
if (ret)
446-
return ret;
464+
goto out_put_table;
447465

448466
platform_set_drvdata(pdev, wdat);
449467

@@ -460,12 +478,16 @@ static int wdat_wdt_probe(struct platform_device *pdev)
460478

461479
ret = wdat_wdt_set_timeout(&wdat->wdd, timeout);
462480
if (ret)
463-
return ret;
481+
goto out_put_table;
464482

465483
watchdog_set_nowayout(&wdat->wdd, nowayout);
466484
watchdog_stop_on_reboot(&wdat->wdd);
467485
watchdog_stop_on_unregister(&wdat->wdd);
468-
return devm_watchdog_register_device(dev, &wdat->wdd);
486+
ret = devm_watchdog_register_device(dev, &wdat->wdd);
487+
488+
out_put_table:
489+
acpi_put_table((struct acpi_table_header *)tbl);
490+
return ret;
469491
}
470492

471493
static int wdat_wdt_suspend_noirq(struct device *dev)

0 commit comments

Comments
 (0)