自己调试的系统偶有死机,跟同事们一起琢磨的结果如下:在evdev.c文件中存在一个隐患的BUG。
static int evdev_open(struct inode *inode, struct file *file)
{
struct evdev *evdev;
struct evdev_client *client;
int i = iminor(inode) - EVDEV_MINOR_BASE;
int error;
if (i >= EVDEV_MINORS)
return -ENODEV;
error = mutex_lock_interruptible(&evdev_table_mutex);
if (error)
return error;
evdev = evdev_table[i];
if (evdev)
get_device(&evdev->dev);
mutex_unlock(&evdev_table_mutex);
if (!evdev)
return -ENODEV;
error = evdev_open_device(evdev);
if (error)
goto err_put_evdev;
client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL);
if (!client) {
error = -ENOMEM;
goto err_put_evdev;
}
spin_lock_init(&client->buffer_lock);
wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, evdev->name);
client->evdev = evdev;
evdev_attach_client(evdev, client);
error = evdev_open_device(evdev);
if (error)
goto err_put_evdev;
file->private_data = client;
return 0;
err_free_client:
evdev_detach_client(evdev, client);
kfree(client);
err_put_evdev:
put_device(&evdev->dev);
return error;
}
可能的问题在于:在wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, evdev->name);中会把wake_lock插入到唤醒锁的链表中,如果在这个语句后面蓝色处还有导致err_free_client的发生,其里面有kfree(client)会把刚插入的那个wake_lock空间也释放,造成链表断裂,引起系统不稳定。所以要将可能导致goto err_put_evdev的evdev_open_device放在插入wake_lock之前,即红色处。