Skip to content

Commit 2c07fd0

Browse files
sudeep-hollagregkh
authored andcommitted
firmware: arm_ffa: Move memory allocation outside the mutex locking
commit 27e850c upstream. The notifier callback node allocation is currently done while holding the notify_lock mutex. While this is safe even if memory allocation may sleep, we need to move the allocation outside the locked region in preparation to move from using muxtes to rwlocks. Move the memory allocation to avoid potential sleeping in atomic context once the locks are moved from mutex to rwlocks. Fixes: e057344 ("firmware: arm_ffa: Add interfaces to request notification callbacks") Message-Id: <[email protected]> Reviewed-by: Jens Wiklander <[email protected]> Signed-off-by: Sudeep Holla <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 076fa20 commit 2c07fd0

File tree

1 file changed

+21
-19
lines changed

1 file changed

+21
-19
lines changed

drivers/firmware/arm_ffa/driver.c

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,12 +1141,11 @@ notifier_hash_node_get(u16 notify_id, enum notify_type type)
11411141
return NULL;
11421142
}
11431143

1144-
static int
1145-
update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb,
1146-
void *cb_data, bool is_registration)
1144+
static int update_notifier_cb(int notify_id, enum notify_type type,
1145+
struct notifier_cb_info *cb)
11471146
{
11481147
struct notifier_cb_info *cb_info = NULL;
1149-
bool cb_found;
1148+
bool cb_found, is_registration = !!cb;
11501149

11511150
cb_info = notifier_hash_node_get(notify_id, type);
11521151
cb_found = !!cb_info;
@@ -1155,15 +1154,7 @@ update_notifier_cb(int notify_id, enum notify_type type, ffa_notifier_cb cb,
11551154
return -EINVAL;
11561155

11571156
if (is_registration) {
1158-
cb_info = kzalloc(sizeof(*cb_info), GFP_KERNEL);
1159-
if (!cb_info)
1160-
return -ENOMEM;
1161-
1162-
cb_info->type = type;
1163-
cb_info->cb = cb;
1164-
cb_info->cb_data = cb_data;
1165-
1166-
hash_add(drv_info->notifier_hash, &cb_info->hnode, notify_id);
1157+
hash_add(drv_info->notifier_hash, &cb->hnode, notify_id);
11671158
} else {
11681159
hash_del(&cb_info->hnode);
11691160
kfree(cb_info);
@@ -1193,7 +1184,7 @@ static int ffa_notify_relinquish(struct ffa_device *dev, int notify_id)
11931184

11941185
mutex_lock(&drv_info->notify_lock);
11951186

1196-
rc = update_notifier_cb(notify_id, type, NULL, NULL, false);
1187+
rc = update_notifier_cb(notify_id, type, NULL);
11971188
if (rc) {
11981189
pr_err("Could not unregister notification callback\n");
11991190
mutex_unlock(&drv_info->notify_lock);
@@ -1212,6 +1203,7 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
12121203
{
12131204
int rc;
12141205
u32 flags = 0;
1206+
struct notifier_cb_info *cb_info = NULL;
12151207
enum notify_type type = ffa_notify_type_get(dev->vm_id);
12161208

12171209
if (ffa_notifications_disabled())
@@ -1220,24 +1212,34 @@ static int ffa_notify_request(struct ffa_device *dev, bool is_per_vcpu,
12201212
if (notify_id >= FFA_MAX_NOTIFICATIONS)
12211213
return -EINVAL;
12221214

1215+
cb_info = kzalloc(sizeof(*cb_info), GFP_KERNEL);
1216+
if (!cb_info)
1217+
return -ENOMEM;
1218+
1219+
cb_info->type = type;
1220+
cb_info->cb_data = cb_data;
1221+
cb_info->cb = cb;
1222+
12231223
mutex_lock(&drv_info->notify_lock);
12241224

12251225
if (is_per_vcpu)
12261226
flags = PER_VCPU_NOTIFICATION_FLAG;
12271227

12281228
rc = ffa_notification_bind(dev->vm_id, BIT(notify_id), flags);
1229-
if (rc) {
1230-
mutex_unlock(&drv_info->notify_lock);
1231-
return rc;
1232-
}
1229+
if (rc)
1230+
goto out_unlock_free;
12331231

1234-
rc = update_notifier_cb(notify_id, type, cb, cb_data, true);
1232+
rc = update_notifier_cb(notify_id, type, cb_info);
12351233
if (rc) {
12361234
pr_err("Failed to register callback for %d - %d\n",
12371235
notify_id, rc);
12381236
ffa_notification_unbind(dev->vm_id, BIT(notify_id));
12391237
}
1238+
1239+
out_unlock_free:
12401240
mutex_unlock(&drv_info->notify_lock);
1241+
if (rc)
1242+
kfree(cb_info);
12411243

12421244
return rc;
12431245
}

0 commit comments

Comments
 (0)