Fix the pddf_custom_wdt driver rarely reports kernel dump issue while reboot in belgite platform (#12322)
Why I did it SONiC will report the kernel dump while system reboot in Belgite platform as the following shows: How I did it Cause: Invalid cdev container pointer from the inode is being accessing in misc device open, which causes a memory corruption in the slub. Because of the slub corruption, random crash is seen during reboot. Fix: - Instead of cdev pointer from the inode, mdev container pointer is used from the file->privdate_data member. Action: update the pddf_custom_wdt driver, How to verify it Do the reboot stress test to check whether there is kernel dump during reboot progress
This commit is contained in:
parent
d7a9f18d18
commit
7fb8bf7012
@ -86,6 +86,7 @@ struct cpld_wdt_private {
|
|||||||
struct platform_device *pdev;
|
struct platform_device *pdev;
|
||||||
struct watchdog_device wddev;
|
struct watchdog_device wddev;
|
||||||
struct cdev cdev;
|
struct cdev cdev;
|
||||||
|
struct miscdevice mdev;
|
||||||
bool suspended;
|
bool suspended;
|
||||||
struct wdt_data wdat;
|
struct wdt_data wdat;
|
||||||
};
|
};
|
||||||
@ -100,7 +101,7 @@ MODULE_PARM_DESC(timeout, "Start watchdog timer on module load with"
|
|||||||
" Zero (default) disables this feature.");
|
" Zero (default) disables this feature.");
|
||||||
|
|
||||||
static bool nowayout = WATCHDOG_NOWAYOUT;
|
static bool nowayout = WATCHDOG_NOWAYOUT;
|
||||||
module_param(nowayout, bool, 0444);
|
module_param(nowayout, bool, 0644);
|
||||||
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
|
MODULE_PARM_DESC(nowayout, "Disable watchdog shutdown on close");
|
||||||
|
|
||||||
static unsigned int watchdog_get_timeleft(struct cpld_wdt_private *wdt)
|
static unsigned int watchdog_get_timeleft(struct cpld_wdt_private *wdt)
|
||||||
@ -114,7 +115,7 @@ static unsigned int watchdog_get_timeleft(struct cpld_wdt_private *wdt)
|
|||||||
time = time << 8 | inb(WDT_TIMER_L_BIT_REG);
|
time = time << 8 | inb(WDT_TIMER_L_BIT_REG);
|
||||||
time = time/1000;
|
time = time/1000;
|
||||||
mutex_unlock(&wdt->wdat.lock);
|
mutex_unlock(&wdt->wdat.lock);
|
||||||
//pr_crit("Watchdog Get Timeleft:%u\n", time);
|
|
||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
static int watchdog_get_timeout(struct cpld_wdt_private *wdt)
|
static int watchdog_get_timeout(struct cpld_wdt_private *wdt)
|
||||||
@ -175,7 +176,7 @@ static int watchdog_ping(struct cpld_wdt_private *wdt)
|
|||||||
outb(WDT_START_FEED, WDT_FEED_REG);
|
outb(WDT_START_FEED, WDT_FEED_REG);
|
||||||
/* stop feed watchdog */
|
/* stop feed watchdog */
|
||||||
outb(WDT_STOP_FEED, WDT_FEED_REG);
|
outb(WDT_STOP_FEED, WDT_FEED_REG);
|
||||||
//pr_crit("Watchdog Ping\n");
|
|
||||||
mutex_unlock(&wdt->wdat.lock);
|
mutex_unlock(&wdt->wdat.lock);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -198,7 +199,7 @@ static void watchdog_keepalive(struct cpld_wdt_private *wdt)
|
|||||||
val &= 0x1;
|
val &= 0x1;
|
||||||
/* start feed watchdog */
|
/* start feed watchdog */
|
||||||
outb(val, WDT_FEED_REG);
|
outb(val, WDT_FEED_REG);
|
||||||
//pr_crit("Watchdog Keepalive\n");
|
|
||||||
mutex_unlock(&wdt->wdat.lock);
|
mutex_unlock(&wdt->wdat.lock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -214,7 +215,7 @@ static int watchdog_start(struct cpld_wdt_private *wdt)
|
|||||||
outb(WDT_ENABLE, WDT_ENABLE_REG);
|
outb(WDT_ENABLE, WDT_ENABLE_REG);
|
||||||
outb(WDT_RESTART, WDT_PUNCH_REG);
|
outb(WDT_RESTART, WDT_PUNCH_REG);
|
||||||
mutex_unlock(&wdt->wdat.lock);
|
mutex_unlock(&wdt->wdat.lock);
|
||||||
//pr_crit("Watchdog Start:Enable and PUNCH\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,7 +227,7 @@ static int watchdog_stop(struct cpld_wdt_private *wdt)
|
|||||||
mutex_lock(&wdt->wdat.lock);
|
mutex_lock(&wdt->wdat.lock);
|
||||||
outb(WDT_DISABLE, WDT_ENABLE_REG);
|
outb(WDT_DISABLE, WDT_ENABLE_REG);
|
||||||
mutex_unlock(&wdt->wdat.lock);
|
mutex_unlock(&wdt->wdat.lock);
|
||||||
//pr_crit("Watchdog Stop\n");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -370,7 +371,7 @@ static int watchdog_open(struct inode *inode, struct file *file)
|
|||||||
{
|
{
|
||||||
struct cpld_wdt_private *wdt;
|
struct cpld_wdt_private *wdt;
|
||||||
|
|
||||||
wdt = container_of(inode->i_cdev, struct cpld_wdt_private, cdev);
|
wdt = container_of(file->private_data, struct cpld_wdt_private, mdev);
|
||||||
|
|
||||||
/* If the watchdog is alive we don't need to start it again */
|
/* If the watchdog is alive we don't need to start it again */
|
||||||
|
|
||||||
@ -384,14 +385,14 @@ static int watchdog_open(struct inode *inode, struct file *file)
|
|||||||
|
|
||||||
wdt->wdat.expect_close = 0;
|
wdt->wdat.expect_close = 0;
|
||||||
|
|
||||||
file->private_data = wdt;
|
|
||||||
return nonseekable_open(inode, file);
|
return nonseekable_open(inode, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int watchdog_release(struct inode *inode, struct file *file)
|
static int watchdog_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct cpld_wdt_private *p;
|
struct cpld_wdt_private *p;
|
||||||
p = (struct cpld_wdt_private *)file->private_data;
|
p = container_of(file->private_data, struct cpld_wdt_private, mdev);
|
||||||
|
|
||||||
if(!p)
|
if(!p)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -423,7 +424,7 @@ static ssize_t watchdog_write(struct file *file, const char __user *buf,
|
|||||||
size_t count, loff_t *ppos)
|
size_t count, loff_t *ppos)
|
||||||
{
|
{
|
||||||
struct cpld_wdt_private *p;
|
struct cpld_wdt_private *p;
|
||||||
p = (struct cpld_wdt_private *)file->private_data;
|
p = container_of(file->private_data, struct cpld_wdt_private, mdev);
|
||||||
|
|
||||||
if(!p)
|
if(!p)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -480,7 +481,7 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd,
|
|||||||
uarg.i = (int __user *)arg;
|
uarg.i = (int __user *)arg;
|
||||||
|
|
||||||
struct cpld_wdt_private *p;
|
struct cpld_wdt_private *p;
|
||||||
p = (struct cpld_wdt_private *)file->private_data;
|
p = container_of(file->private_data, struct cpld_wdt_private, mdev);
|
||||||
if(!p)
|
if(!p)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -627,8 +628,8 @@ static int cpld_wdt_probe(struct platform_device *pdev)
|
|||||||
err = register_reboot_notifier(&watchdog_notifier);
|
err = register_reboot_notifier(&watchdog_notifier);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
p->mdev = watchdog_miscdev;
|
||||||
err = misc_register(&watchdog_miscdev);
|
err = misc_register(&p->mdev);
|
||||||
if (err) {
|
if (err) {
|
||||||
pr_err("cannot register miscdev on minor=%d\n",
|
pr_err("cannot register miscdev on minor=%d\n",
|
||||||
watchdog_miscdev.minor);
|
watchdog_miscdev.minor);
|
||||||
@ -672,7 +673,7 @@ static int cpld_wdt_remove(struct platform_device *pdev)
|
|||||||
|
|
||||||
sysfs_remove_group(&pdev->dev.kobj, &wdt_group);
|
sysfs_remove_group(&pdev->dev.kobj, &wdt_group);
|
||||||
|
|
||||||
misc_deregister(&watchdog_miscdev);
|
misc_deregister(&p->mdev);
|
||||||
|
|
||||||
unregister_reboot_notifier(&watchdog_notifier);
|
unregister_reboot_notifier(&watchdog_notifier);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user