summaryrefslogtreecommitdiff
path: root/aoc.c
diff options
context:
space:
mode:
authoryixuanjiang <yixuanjiang@google.com>2021-12-15 14:28:53 +0800
committerRoger Liao <rogerliao@google.com>2022-05-10 05:44:58 +0800
commitc59744779c7c4587a74a50c9acd13926eb6475bc (patch)
tree271dc6ff3fd98cfca74afa6ff84dbea895f67bd4 /aoc.c
parentd2a8bfc8a8e306edd59ac0e8adcaecf9ee45911b (diff)
downloadaoc-c59744779c7c4587a74a50c9acd13926eb6475bc.tar.gz
aoc: add protect on service read/write timeout
Prevent NULL pointer during aoc SSR Block free flow when service write read active Bug: 209403953 Signed-off-by: yixuanjiang <yixuanjiang@google.com> Change-Id: Ib0a0f4082018fc237cdd789c7dfba3cee03d760b
Diffstat (limited to 'aoc.c')
-rw-r--r--aoc.c47
1 files changed, 26 insertions, 21 deletions
diff --git a/aoc.c b/aoc.c
index f055aaf..90ba0ee 100644
--- a/aoc.c
+++ b/aoc.c
@@ -135,7 +135,7 @@ struct aoc_prvdata {
void *map_handler_ctx;
struct delayed_work monitor_work;
- bool aoc_process_active;
+ atomic_t aoc_process_active;
struct device *dev;
struct iommu_domain *domain;
@@ -1073,7 +1073,6 @@ EXPORT_SYMBOL_GPL(aoc_service_read);
ssize_t aoc_service_read_timeout(struct aoc_service_dev *dev, uint8_t *buffer,
size_t count, long timeout)
{
- const struct device *parent;
struct aoc_prvdata *prvdata;
aoc_service *service;
@@ -1087,16 +1086,19 @@ ssize_t aoc_service_read_timeout(struct aoc_service_dev *dev, uint8_t *buffer,
if (dev->dead)
return -ENODEV;
- mutex_lock(&aoc_service_lock);
+ if (!aoc_platform_device)
+ return -ENODEV;
+
+ prvdata = platform_get_drvdata(aoc_platform_device);
+ if (!prvdata)
+ return -ENODEV;
- if (aoc_state != AOC_STATE_ONLINE) {
+ atomic_inc(&prvdata->aoc_process_active);
+ if (aoc_state != AOC_STATE_ONLINE || work_busy(&prvdata->watchdog_work)) {
ret = -EBUSY;
goto err;
}
- parent = dev->dev.parent;
- prvdata = dev_get_drvdata(parent);
-
service_number = dev->service_index;
service = service_at_index(prvdata, dev->service_index);
@@ -1147,7 +1149,7 @@ ssize_t aoc_service_read_timeout(struct aoc_service_dev *dev, uint8_t *buffer,
&msg_size);
err:
- mutex_unlock(&aoc_service_lock);
+ atomic_dec(&prvdata->aoc_process_active);
if (ret < 0)
return ret;
@@ -1232,7 +1234,6 @@ EXPORT_SYMBOL_GPL(aoc_service_write);
ssize_t aoc_service_write_timeout(struct aoc_service_dev *dev, const uint8_t *buffer,
size_t count, long timeout)
{
- const struct device *parent;
struct aoc_prvdata *prvdata;
aoc_service *service;
@@ -1246,15 +1247,19 @@ ssize_t aoc_service_write_timeout(struct aoc_service_dev *dev, const uint8_t *bu
if (dev->dead)
return -ENODEV;
- mutex_lock(&aoc_service_lock);
- if (aoc_state != AOC_STATE_ONLINE) {
- ret = -ENODEV;
+ if (!aoc_platform_device)
+ return -ENODEV;
+
+ prvdata = platform_get_drvdata(aoc_platform_device);
+ if (!prvdata)
+ return -ENODEV;
+
+ atomic_inc(&prvdata->aoc_process_active);
+ if (aoc_state != AOC_STATE_ONLINE || work_busy(&prvdata->watchdog_work)) {
+ ret = -EBUSY;
goto err;
}
- parent = dev->dev.parent;
- prvdata = dev_get_drvdata(parent);
-
service_number = dev->service_index;
service = service_at_index(prvdata, service_number);
@@ -1304,7 +1309,7 @@ ssize_t aoc_service_write_timeout(struct aoc_service_dev *dev, const uint8_t *bu
signal_aoc(prvdata->mbox_channels[interrupt].channel);
err:
- mutex_unlock(&aoc_service_lock);
+ atomic_dec(&prvdata->aoc_process_active);
if (ret < 0)
return ret;
@@ -2338,8 +2343,8 @@ static void aoc_take_offline(struct aoc_prvdata *prvdata)
pr_notice("taking aoc offline\n");
aoc_state = AOC_STATE_OFFLINE;
- /* wait until aoc_process_services finish */
- while (prvdata->aoc_process_active);
+ /* wait until aoc_process or service write/read finish */
+ while (!!atomic_read(&prvdata->aoc_process_active));
bus_for_each_dev(&aoc_bus_type, NULL, NULL, aoc_remove_device);
@@ -2375,11 +2380,11 @@ static void aoc_process_services(struct aoc_prvdata *prvdata, int offset)
int services;
int i;
+ atomic_inc(&prvdata->aoc_process_active);
+
if (aoc_state != AOC_STATE_ONLINE || work_busy(&prvdata->watchdog_work))
goto exit;
- prvdata->aoc_process_active = true;
-
services = aoc_num_services();
for (i = 0; i < services; i++) {
service_dev = service_dev_at_index(prvdata, i);
@@ -2400,7 +2405,7 @@ static void aoc_process_services(struct aoc_prvdata *prvdata, int offset)
}
}
exit:
- prvdata->aoc_process_active = false;
+ atomic_dec(&prvdata->aoc_process_active);
}
void aoc_set_map_handler(struct aoc_service_dev *dev, aoc_map_handler handler,