From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: padmarao edapalapati Date: Thu, 6 Sep 2018 10:38:22 +0530 Subject: [PATCH] Fix for cbc kernel driver crash during warm reboot Added a Sync mechanism with spinlocks between demuxed_receive and cbc_device_open, cbc_device_release Change-Id: Id5c71eb59bb390a0b39b7bc66d5536d9eecf607f Signed-off-by: padmarao edapalapati --- drivers/tty/cbc/cbc_device.c | 4 +++- drivers/tty/cbc/cbc_device.h | 3 +++ drivers/tty/cbc/cbc_device_manager.c | 12 ++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/tty/cbc/cbc_device.c b/drivers/tty/cbc/cbc_device.c index 1933a8527015..23728c04dd6e 100644 --- a/drivers/tty/cbc/cbc_device.c +++ b/drivers/tty/cbc/cbc_device.c @@ -18,8 +18,10 @@ void cbc_device_init(struct cbc_device_data *cd) { - if (cd) + if (cd) { + spin_lock_init(&cd->cbc_device_lock); INIT_LIST_HEAD(&cd->open_files_head); + } } void cbc_file_init(struct cbc_file_data *file) diff --git a/drivers/tty/cbc/cbc_device.h b/drivers/tty/cbc/cbc_device.h index deb0cd922316..09c806716557 100644 --- a/drivers/tty/cbc/cbc_device.h +++ b/drivers/tty/cbc/cbc_device.h @@ -22,6 +22,7 @@ #include #include #include +#include #include "cbc_types.h" @@ -49,6 +50,8 @@ struct cbc_device_data { char *device_name; enum cbc_device_type device_type; struct device *device; + /* lock to sync demuxed_receive with cbc_device_release and open */ + spinlock_t cbc_device_lock; struct list_head open_files_head; }; diff --git a/drivers/tty/cbc/cbc_device_manager.c b/drivers/tty/cbc/cbc_device_manager.c index 0e74183d9828..2c8c1cf966ca 100644 --- a/drivers/tty/cbc/cbc_device_manager.c +++ b/drivers/tty/cbc/cbc_device_manager.c @@ -234,6 +234,7 @@ static int cbc_device_open(struct inode *inode, struct file *file) inode->i_rdev)]; int ret = 0; u32 num_open_files = 0; + unsigned long flags; struct cbc_file_data *file_data = kmalloc(sizeof(struct cbc_file_data), GFP_KERNEL); @@ -267,7 +268,9 @@ static int cbc_device_open(struct inode *inode, struct file *file) if (ret == 0) { cbc_file_init(file_data); file_data->cbc_device = device_data; + spin_lock_irqsave(&device_data->cbc_device_lock, flags); list_add(&file_data->list, &device_data->open_files_head); + spin_unlock_irqrestore(&device_data->cbc_device_lock, flags); file->private_data = file_data; } else { kfree(file_data); @@ -285,9 +288,14 @@ static int cbc_device_release(struct inode *inode, struct file *file) { u32 dev_idx = MINOR(inode->i_rdev); struct cbc_file_data *file_data = file->private_data; + unsigned long flags; if (file_data) { + spin_lock_irqsave( + &file_data->cbc_device->cbc_device_lock, flags); list_del(&file_data->list); + spin_unlock_irqrestore( + &file_data->cbc_device->cbc_device_lock, flags); pr_debug("cbc-core: device_release: %d.%d %s\n", MAJOR(inode->i_rdev), dev_idx, @@ -299,6 +307,7 @@ static int cbc_device_release(struct inode *inode, struct file *file) kfree(file_data); file->private_data = NULL; } + return 0; } @@ -796,6 +805,7 @@ static void demuxed_receive(void *void_data, struct cbc_buffer *cbc_buffer) (struct cbc_device_data *) void_data; struct list_head *current_item; struct cbc_file_data *current_file_data; + unsigned long flags; if (device_data && cbc_buffer && cbc_buffer->frame_length > @@ -836,6 +846,7 @@ static void demuxed_receive(void *void_data, struct cbc_buffer *cbc_buffer) /* else, do not touch payload_length in a debug-channel */ /* Enqueue */ + spin_lock_irqsave(&device_data->cbc_device_lock, flags); for (current_item = device_data->open_files_head.next ; current_item != &device_data->open_files_head; current_item = current_item->next) { @@ -845,6 +856,7 @@ static void demuxed_receive(void *void_data, struct cbc_buffer *cbc_buffer) /* File_enqueue increases ref. count. */ cbc_file_enqueue(current_file_data, cbc_buffer); } + spin_unlock_irqrestore(&device_data->cbc_device_lock, flags); } else { pr_err("cbc-core: (<- IOC) dev_receive data is null\n"); } -- https://clearlinux.org