[WATCHDOG] Semi-typical watchdog bug re early misc_register()
It seems that some watchdog drivers are doing following mistake: rv = misc_register(); if (rv < 0) return rv; rv = request_region(); if (rv < 0) { misc_deregister(); return rv; } But, right after misc_register() returns, misc device can be opened and ioctls interacting with hardware issued, and driver can do outb() to port it doesn't own yet, because request_region() is still pending. Here is my patch, compile-tested only. Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
This commit is contained in:
parent
0e94f2ee0d
commit
fb8f7ba077
@ -220,17 +220,17 @@ static int __devinit cpu5wdt_init(void)
|
|||||||
if ( verbose )
|
if ( verbose )
|
||||||
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
|
printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose);
|
||||||
|
|
||||||
if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
|
|
||||||
printk(KERN_ERR PFX "misc_register failed\n");
|
|
||||||
goto no_misc;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
|
if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) {
|
||||||
printk(KERN_ERR PFX "request_region failed\n");
|
printk(KERN_ERR PFX "request_region failed\n");
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
goto no_port;
|
goto no_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) {
|
||||||
|
printk(KERN_ERR PFX "misc_register failed\n");
|
||||||
|
goto no_misc;
|
||||||
|
}
|
||||||
|
|
||||||
/* watchdog reboot? */
|
/* watchdog reboot? */
|
||||||
val = inb(port + CPU5WDT_STATUS_REG);
|
val = inb(port + CPU5WDT_STATUS_REG);
|
||||||
val = (val >> 2) & 1;
|
val = (val >> 2) & 1;
|
||||||
@ -250,9 +250,9 @@ static int __devinit cpu5wdt_init(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
no_port:
|
|
||||||
misc_deregister(&cpu5wdt_misc);
|
|
||||||
no_misc:
|
no_misc:
|
||||||
|
release_region(port, CPU5WDT_EXTENT);
|
||||||
|
no_port:
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -413,17 +413,10 @@ static int __init eurwdt_init(void)
|
|||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ret = misc_register(&eurwdt_miscdev);
|
|
||||||
if (ret) {
|
|
||||||
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
|
|
||||||
WATCHDOG_MINOR);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
|
ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
|
printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq);
|
||||||
goto outmisc;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_region(io, 2, "eurwdt")) {
|
if (!request_region(io, 2, "eurwdt")) {
|
||||||
@ -438,6 +431,13 @@ static int __init eurwdt_init(void)
|
|||||||
goto outreg;
|
goto outreg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = misc_register(&eurwdt_miscdev);
|
||||||
|
if (ret) {
|
||||||
|
printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n",
|
||||||
|
WATCHDOG_MINOR);
|
||||||
|
goto outreboot;
|
||||||
|
}
|
||||||
|
|
||||||
eurwdt_unlock_chip();
|
eurwdt_unlock_chip();
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
@ -448,14 +448,14 @@ static int __init eurwdt_init(void)
|
|||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
outreboot:
|
||||||
|
unregister_reboot_notifier(&eurwdt_notifier);
|
||||||
|
|
||||||
outreg:
|
outreg:
|
||||||
release_region(io, 2);
|
release_region(io, 2);
|
||||||
|
|
||||||
outirq:
|
outirq:
|
||||||
free_irq(irq, NULL);
|
free_irq(irq, NULL);
|
||||||
|
|
||||||
outmisc:
|
|
||||||
misc_deregister(&eurwdt_miscdev);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,18 +367,17 @@ static int __init ibmasr_init(void)
|
|||||||
if (!asr_type)
|
if (!asr_type)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
rc = asr_get_base_address();
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
rc = misc_register(&asr_miscdev);
|
rc = misc_register(&asr_miscdev);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
|
release_region(asr_base, asr_length);
|
||||||
printk(KERN_ERR PFX "failed to register misc device\n");
|
printk(KERN_ERR PFX "failed to register misc device\n");
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = asr_get_base_address();
|
|
||||||
if (rc) {
|
|
||||||
misc_deregister(&asr_miscdev);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,13 +440,6 @@ static int __init zf_init(void)
|
|||||||
spin_lock_init(&zf_lock);
|
spin_lock_init(&zf_lock);
|
||||||
spin_lock_init(&zf_port_lock);
|
spin_lock_init(&zf_port_lock);
|
||||||
|
|
||||||
ret = misc_register(&zf_miscdev);
|
|
||||||
if (ret){
|
|
||||||
printk(KERN_ERR "can't misc_register on minor=%d\n",
|
|
||||||
WATCHDOG_MINOR);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
|
if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){
|
||||||
printk(KERN_ERR "cannot reserve I/O ports at %d\n",
|
printk(KERN_ERR "cannot reserve I/O ports at %d\n",
|
||||||
ZF_IOBASE);
|
ZF_IOBASE);
|
||||||
@ -461,16 +454,23 @@ static int __init zf_init(void)
|
|||||||
goto no_reboot;
|
goto no_reboot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = misc_register(&zf_miscdev);
|
||||||
|
if (ret){
|
||||||
|
printk(KERN_ERR "can't misc_register on minor=%d\n",
|
||||||
|
WATCHDOG_MINOR);
|
||||||
|
goto no_misc;
|
||||||
|
}
|
||||||
|
|
||||||
zf_set_status(0);
|
zf_set_status(0);
|
||||||
zf_set_control(0);
|
zf_set_control(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
no_misc:
|
||||||
|
unregister_reboot_notifier(&zf_notifier);
|
||||||
no_reboot:
|
no_reboot:
|
||||||
release_region(ZF_IOBASE, 3);
|
release_region(ZF_IOBASE, 3);
|
||||||
no_region:
|
no_region:
|
||||||
misc_deregister(&zf_miscdev);
|
|
||||||
out:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,18 +333,17 @@ static int __init sbc8360_init(void)
|
|||||||
int res;
|
int res;
|
||||||
unsigned long int mseconds = 60000;
|
unsigned long int mseconds = 60000;
|
||||||
|
|
||||||
spin_lock_init(&sbc8360_lock);
|
if (timeout < 0 || timeout > 63) {
|
||||||
res = misc_register(&sbc8360_miscdev);
|
printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
|
||||||
if (res) {
|
res = -EINVAL;
|
||||||
printk(KERN_ERR PFX "failed to register misc device\n");
|
goto out;
|
||||||
goto out_nomisc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
|
if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) {
|
||||||
printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
|
printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n",
|
||||||
SBC8360_ENABLE);
|
SBC8360_ENABLE);
|
||||||
res = -EIO;
|
res = -EIO;
|
||||||
goto out_noenablereg;
|
goto out;
|
||||||
}
|
}
|
||||||
if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
|
if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) {
|
||||||
printk(KERN_ERR PFX
|
printk(KERN_ERR PFX
|
||||||
@ -360,10 +359,11 @@ static int __init sbc8360_init(void)
|
|||||||
goto out_noreboot;
|
goto out_noreboot;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout < 0 || timeout > 63) {
|
spin_lock_init(&sbc8360_lock);
|
||||||
printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n");
|
res = misc_register(&sbc8360_miscdev);
|
||||||
res = -EINVAL;
|
if (res) {
|
||||||
goto out_noreboot;
|
printk(KERN_ERR PFX "failed to register misc device\n");
|
||||||
|
goto out_nomisc;
|
||||||
}
|
}
|
||||||
|
|
||||||
wd_margin = wd_times[timeout][0];
|
wd_margin = wd_times[timeout][0];
|
||||||
@ -383,13 +383,13 @@ static int __init sbc8360_init(void)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
out_noreboot:
|
|
||||||
release_region(SBC8360_ENABLE, 1);
|
|
||||||
release_region(SBC8360_BASETIME, 1);
|
|
||||||
out_noenablereg:
|
|
||||||
out_nobasetimereg:
|
|
||||||
misc_deregister(&sbc8360_miscdev);
|
|
||||||
out_nomisc:
|
out_nomisc:
|
||||||
|
unregister_reboot_notifier(&sbc8360_notifier);
|
||||||
|
out_noreboot:
|
||||||
|
release_region(SBC8360_BASETIME, 1);
|
||||||
|
out_nobasetimereg:
|
||||||
|
release_region(SBC8360_ENABLE, 1);
|
||||||
|
out:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user