diff options
| author | Skylar Chang <chiaweic@codeaurora.org> | 2016-06-14 18:49:20 -0700 |
|---|---|---|
| committer | Kyle Yan <kyan@codeaurora.org> | 2016-06-22 14:44:45 -0700 |
| commit | 15dd3b14deac7ee565e3eb5a3e40d35a790dc92c (patch) | |
| tree | dead00fc3544452a094459346f33a52f51ad669b /drivers/platform | |
| parent | ea6de85a0be106308347090b50e9da9363a0e8ca (diff) | |
msm: ipa: fix delete dependency race condition
IPA RM dependencies are added both by kernel drivers and by
userspace application (IPACM), depending on the use case.
On rare condition, a race is possible between adding the dependency
and deleting it, which results in a bad state of the dependency graph.
This change makes sure that dependency is deleted only if it was added
by the same entity.
CRs-Fixed: 1027773
Change-Id: I9253469887b8913f6f2c513a6c7043ed60400b8a
Acked-by Ady Abraham <adya@qti.qualcomm.com>
Signed-off-by: Skylar Chang <chiaweic@codeaurora.org>
Diffstat (limited to 'drivers/platform')
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm.c | 144 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_dependency_graph.c | 16 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_dependency_graph.h | 8 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_i.h | 6 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_peers_list.c | 58 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_peers_list.h | 17 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_resource.c | 57 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_rm_resource.h | 6 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v2/ipa.c | 8 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa.c | 8 |
10 files changed, 253 insertions, 75 deletions
diff --git a/drivers/platform/msm/ipa/ipa_rm.c b/drivers/platform/msm/ipa/ipa_rm.c index d0bde0e9654b..a9813311f156 100644 --- a/drivers/platform/msm/ipa/ipa_rm.c +++ b/drivers/platform/msm/ipa/ipa_rm.c @@ -172,19 +172,9 @@ bail: } EXPORT_SYMBOL(ipa_rm_delete_resource); -/** - * ipa_rm_add_dependency() - create dependency - * between 2 resources - * @resource_name: name of dependent resource - * @depends_on_name: name of its dependency - * - * Returns: 0 on success, negative on failure - * - * Side effects: IPA_RM_RESORCE_GRANTED could be generated - * in case client registered with IPA RM - */ -int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name) +static int _ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name, + bool userspace_dep) { unsigned long flags; int result; @@ -200,29 +190,53 @@ int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name, result = ipa_rm_dep_graph_add_dependency( ipa_rm_ctx->dep_graph, resource_name, - depends_on_name); + depends_on_name, + userspace_dep); spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags); IPA_RM_DBG("EXIT with %d\n", result); return result; } + +/** + * ipa_rm_add_dependency() - create dependency between 2 resources + * @resource_name: name of dependent resource + * @depends_on_name: name of its dependency + * + * Returns: 0 on success, negative on failure + * + * Side effects: IPA_RM_RESORCE_GRANTED could be generated + * in case client registered with IPA RM + */ +int ipa_rm_add_dependency(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_add_dependency(resource_name, depends_on_name, false); +} EXPORT_SYMBOL(ipa_rm_add_dependency); /** - * ipa_rm_add_dependency_sync() - Create a dependency between 2 resources - * in a synchronized fashion. In case a producer resource is in GRANTED state - * and the newly added consumer resource is in RELEASED state, the consumer - * entity will be requested and the function will block until the consumer - * is granted. + * ipa_rm_add_dependency_from_ioctl() - create dependency between 2 resources * @resource_name: name of dependent resource * @depends_on_name: name of its dependency * + * This function is expected to be called from IOCTL and the dependency will be + * marked as is was added by the userspace. + * * Returns: 0 on success, negative on failure * - * Side effects: May block. See documentation above. + * Side effects: IPA_RM_RESORCE_GRANTED could be generated + * in case client registered with IPA RM */ -int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name) +int ipa_rm_add_dependency_from_ioctl(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_add_dependency(resource_name, depends_on_name, true); +} + +static int _ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name, + bool userspsace_dep) { int result; struct ipa_rm_resource *consumer; @@ -240,7 +254,8 @@ int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, result = ipa_rm_dep_graph_add_dependency( ipa_rm_ctx->dep_graph, resource_name, - depends_on_name); + depends_on_name, + userspsace_dep); spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags); if (result == -EINPROGRESS) { ipa_rm_dep_graph_get_resource(ipa_rm_ctx->dep_graph, @@ -268,21 +283,54 @@ int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, return result; } +/** + * ipa_rm_add_dependency_sync() - Create a dependency between 2 resources + * in a synchronized fashion. In case a producer resource is in GRANTED state + * and the newly added consumer resource is in RELEASED state, the consumer + * entity will be requested and the function will block until the consumer + * is granted. + * @resource_name: name of dependent resource + * @depends_on_name: name of its dependency + * + * This function is expected to be called from IOCTL and the dependency will be + * marked as is was added by the userspace. + * + * Returns: 0 on success, negative on failure + * + * Side effects: May block. See documentation above. + */ +int ipa_rm_add_dependency_sync(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_add_dependency_sync(resource_name, depends_on_name, + false); +} EXPORT_SYMBOL(ipa_rm_add_dependency_sync); /** - * ipa_rm_delete_dependency() - create dependency - * between 2 resources + * ipa_rm_add_dependency_sync_from_ioctl() - Create a dependency between 2 + * resources in a synchronized fashion. In case a producer resource is in + * GRANTED state and the newly added consumer resource is in RELEASED state, + * the consumer entity will be requested and the function will block until + * the consumer is granted. * @resource_name: name of dependent resource * @depends_on_name: name of its dependency * * Returns: 0 on success, negative on failure * - * Side effects: IPA_RM_RESORCE_GRANTED could be generated - * in case client registered with IPA RM + * Side effects: May block. See documentation above. */ -int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name) +int ipa_rm_add_dependency_sync_from_ioctl( + enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_add_dependency_sync(resource_name, depends_on_name, + true); +} + +static int _ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name, + bool userspace_dep) { unsigned long flags; int result; @@ -298,15 +346,51 @@ int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name, result = ipa_rm_dep_graph_delete_dependency( ipa_rm_ctx->dep_graph, resource_name, - depends_on_name); + depends_on_name, + userspace_dep); spin_unlock_irqrestore(&ipa_rm_ctx->ipa_rm_lock, flags); IPA_RM_DBG("EXIT with %d\n", result); return result; } + +/** + * ipa_rm_delete_dependency() - delete dependency between 2 resources + * @resource_name: name of dependent resource + * @depends_on_name: name of its dependency + * + * Returns: 0 on success, negative on failure + * + * Side effects: IPA_RM_RESORCE_GRANTED could be generated + * in case client registered with IPA RM + */ +int ipa_rm_delete_dependency(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_delete_dependency(resource_name, depends_on_name, false); +} EXPORT_SYMBOL(ipa_rm_delete_dependency); /** + * ipa_rm_delete_dependency_fron_ioctl() - delete dependency between 2 resources + * @resource_name: name of dependent resource + * @depends_on_name: name of its dependency + * + * This function is expected to be called from IOCTL and the dependency will be + * marked as is was added by the userspace. + * + * Returns: 0 on success, negative on failure + * + * Side effects: IPA_RM_RESORCE_GRANTED could be generated + * in case client registered with IPA RM + */ +int ipa_rm_delete_dependency_from_ioctl(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name) +{ + return _ipa_rm_delete_dependency(resource_name, depends_on_name, true); +} + +/** * ipa_rm_request_resource() - request resource * @resource_name: [in] name of the requested resource * diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c index fd437b0c8775..54cad888cb7f 100644 --- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c +++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -152,12 +152,14 @@ int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph, * @graph: [in] dependency graph * @resource_name: [in] resource to add * @depends_on_name: [in] resource to add + * @userspace_dep: [in] operation requested by userspace ? * * Returns: 0 on success, negative on failure */ int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph, enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name) + enum ipa_rm_resource_name depends_on_name, + bool userspace_dep) { struct ipa_rm_resource *dependent = NULL; struct ipa_rm_resource *dependency = NULL; @@ -186,7 +188,8 @@ int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph, result = -EINVAL; goto bail; } - result = ipa_rm_resource_add_dependency(dependent, dependency); + result = ipa_rm_resource_add_dependency(dependent, dependency, + userspace_dep); bail: IPA_RM_DBG("EXIT with %d\n", result); @@ -199,13 +202,15 @@ bail: * @graph: [in] dependency graph * @resource_name: [in] resource to delete * @depends_on_name: [in] resource to delete + * @userspace_dep: [in] operation requested by userspace ? * * Returns: 0 on success, negative on failure * */ int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph, enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name) + enum ipa_rm_resource_name depends_on_name, + bool userspace_dep) { struct ipa_rm_resource *dependent = NULL; struct ipa_rm_resource *dependency = NULL; @@ -237,7 +242,8 @@ int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph, goto bail; } - result = ipa_rm_resource_delete_dependency(dependent, dependency); + result = ipa_rm_resource_delete_dependency(dependent, dependency, + userspace_dep); bail: IPA_RM_DBG("EXIT with %d\n", result); diff --git a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h index b76c6636f873..e322d813e4ea 100644 --- a/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h +++ b/drivers/platform/msm/ipa/ipa_rm_dependency_graph.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -38,10 +38,12 @@ int ipa_rm_dep_graph_remove(struct ipa_rm_dep_graph *graph, int ipa_rm_dep_graph_add_dependency(struct ipa_rm_dep_graph *graph, enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name); + enum ipa_rm_resource_name depends_on_name, + bool userspsace_dep); int ipa_rm_dep_graph_delete_dependency(struct ipa_rm_dep_graph *graph, enum ipa_rm_resource_name resource_name, - enum ipa_rm_resource_name depends_on_name); + enum ipa_rm_resource_name depends_on_name, + bool userspsace_dep); #endif /* _IPA_RM_DEPENDENCY_GRAPH_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_rm_i.h b/drivers/platform/msm/ipa/ipa_rm_i.h index e0c1582e8543..eb86c54d7382 100644 --- a/drivers/platform/msm/ipa/ipa_rm_i.h +++ b/drivers/platform/msm/ipa/ipa_rm_i.h @@ -146,6 +146,12 @@ int ipa_rm_request_resource_with_timer(enum ipa_rm_resource_name resource_name); void delayed_release_work_func(struct work_struct *work); +int ipa_rm_add_dependency_from_ioctl(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name); + +int ipa_rm_delete_dependency_from_ioctl(enum ipa_rm_resource_name resource_name, + enum ipa_rm_resource_name depends_on_name); + void ipa_rm_exit(void); #endif /* _IPA_RM_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.c b/drivers/platform/msm/ipa/ipa_rm_peers_list.c index 51ad9530f6ee..fe8e781c4db0 100644 --- a/drivers/platform/msm/ipa/ipa_rm_peers_list.c +++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.c @@ -68,7 +68,7 @@ int ipa_rm_peers_list_create(int max_peers, (*peers_list)->max_peers = max_peers; (*peers_list)->peers = kzalloc((*peers_list)->max_peers * - sizeof(struct ipa_rm_resource *), GFP_ATOMIC); + sizeof(*((*peers_list)->peers)), GFP_ATOMIC); if (!((*peers_list)->peers)) { IPA_RM_ERR("no mem\n"); result = -ENOMEM; @@ -112,7 +112,9 @@ void ipa_rm_peers_list_remove_peer( return; peers_list->peers[ipa_rm_peers_list_get_resource_index( - resource_name)] = NULL; + resource_name)].resource = NULL; + peers_list->peers[ipa_rm_peers_list_get_resource_index( + resource_name)].userspace_dep = false; peers_list->peers_count--; } @@ -125,14 +127,16 @@ void ipa_rm_peers_list_remove_peer( */ void ipa_rm_peers_list_add_peer( struct ipa_rm_peers_list *peers_list, - struct ipa_rm_resource *resource) + struct ipa_rm_resource *resource, + bool userspace_dep) { if (!peers_list || !resource) return; peers_list->peers[ipa_rm_peers_list_get_resource_index( - resource->name)] = - resource; + resource->name)].resource = resource; + peers_list->peers[ipa_rm_peers_list_get_resource_index( + resource->name)].userspace_dep = userspace_dep; peers_list->peers_count++; } @@ -186,6 +190,7 @@ bail: * @resource_name: first peers list resource name * @depends_on_peers: second peers list * @depends_on_name: second peers list resource name + * @userspace_dep: [out] dependency was created by userspace * * Returns: true if there is dependency, false otherwise * @@ -194,20 +199,28 @@ bool ipa_rm_peers_list_check_dependency( struct ipa_rm_peers_list *resource_peers, enum ipa_rm_resource_name resource_name, struct ipa_rm_peers_list *depends_on_peers, - enum ipa_rm_resource_name depends_on_name) + enum ipa_rm_resource_name depends_on_name, + bool *userspace_dep) { bool result = false; + int resource_index; - if (!resource_peers || !depends_on_peers) + if (!resource_peers || !depends_on_peers || !userspace_dep) return result; - if (resource_peers->peers[ipa_rm_peers_list_get_resource_index( - depends_on_name)] != NULL) + resource_index = ipa_rm_peers_list_get_resource_index(depends_on_name); + if (resource_peers->peers[resource_index].resource != NULL) { result = true; + *userspace_dep = resource_peers->peers[resource_index]. + userspace_dep; + } - if (depends_on_peers->peers[ipa_rm_peers_list_get_resource_index( - resource_name)] != NULL) + resource_index = ipa_rm_peers_list_get_resource_index(resource_name); + if (depends_on_peers->peers[resource_index].resource != NULL) { result = true; + *userspace_dep = depends_on_peers->peers[resource_index]. + userspace_dep; + } return result; } @@ -228,7 +241,28 @@ struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index, if (!ipa_rm_peers_list_check_index(resource_index, resource_peers)) goto bail; - result = resource_peers->peers[resource_index]; + result = resource_peers->peers[resource_index].resource; +bail: + return result; +} + +/** + * ipa_rm_peers_list_get_userspace_dep() - returns whether resource dependency + * was added by userspace + * @resource_index: resource index + * @resource_peers: peers list + * + * Returns: true if dependency was added by userspace, false by kernel + */ +bool ipa_rm_peers_list_get_userspace_dep(int resource_index, + struct ipa_rm_peers_list *resource_peers) +{ + bool result = false; + + if (!ipa_rm_peers_list_check_index(resource_index, resource_peers)) + goto bail; + + result = resource_peers->peers[resource_index].userspace_dep; bail: return result; } diff --git a/drivers/platform/msm/ipa/ipa_rm_peers_list.h b/drivers/platform/msm/ipa/ipa_rm_peers_list.h index b41de0aa3167..cf1c157174dc 100644 --- a/drivers/platform/msm/ipa/ipa_rm_peers_list.h +++ b/drivers/platform/msm/ipa/ipa_rm_peers_list.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -15,6 +15,11 @@ #include "ipa_rm_resource.h" +struct ipa_rm_resource_peer { + struct ipa_rm_resource *resource; + bool userspace_dep; +}; + /** * struct ipa_rm_peers_list - IPA RM resource peers list * @peers: the list of references to resources dependent on this resource @@ -23,7 +28,7 @@ * @peers_count: actual number of peers for this resource */ struct ipa_rm_peers_list { - struct ipa_rm_resource **peers; + struct ipa_rm_resource_peer *peers; int max_peers; int peers_count; }; @@ -36,14 +41,18 @@ void ipa_rm_peers_list_remove_peer( enum ipa_rm_resource_name resource_name); void ipa_rm_peers_list_add_peer( struct ipa_rm_peers_list *peers_list, - struct ipa_rm_resource *resource); + struct ipa_rm_resource *resource, + bool userspace_dep); bool ipa_rm_peers_list_check_dependency( struct ipa_rm_peers_list *resource_peers, enum ipa_rm_resource_name resource_name, struct ipa_rm_peers_list *depends_on_peers, - enum ipa_rm_resource_name depends_on_name); + enum ipa_rm_resource_name depends_on_name, + bool *userspace_dep); struct ipa_rm_resource *ipa_rm_peers_list_get_resource(int resource_index, struct ipa_rm_peers_list *peers_list); +bool ipa_rm_peers_list_get_userspace_dep(int resource_index, + struct ipa_rm_peers_list *resource_peers); int ipa_rm_peers_list_get_size(struct ipa_rm_peers_list *peers_list); bool ipa_rm_peers_list_is_empty(struct ipa_rm_peers_list *peers_list); bool ipa_rm_peers_list_has_last_peer( diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.c b/drivers/platform/msm/ipa/ipa_rm_resource.c index 597598df6997..cc00f8cf7fb6 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.c +++ b/drivers/platform/msm/ipa/ipa_rm_resource.c @@ -446,6 +446,7 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource) int peers_index; int result = 0; int list_size; + bool userspace_dep; if (!resource) { IPA_RM_ERR("invalid params\n"); @@ -464,10 +465,16 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource) consumer = ipa_rm_peers_list_get_resource( peers_index, resource->peers_list); - if (consumer) + if (consumer) { + userspace_dep = + ipa_rm_peers_list_get_userspace_dep( + peers_index, + resource->peers_list); ipa_rm_resource_delete_dependency( resource, - consumer); + consumer, + userspace_dep); + } } } @@ -483,10 +490,16 @@ int ipa_rm_resource_delete(struct ipa_rm_resource *resource) producer = ipa_rm_peers_list_get_resource( peers_index, resource->peers_list); - if (producer) + if (producer) { + userspace_dep = + ipa_rm_peers_list_get_userspace_dep( + peers_index, + resource->peers_list); ipa_rm_resource_delete_dependency( producer, - resource); + resource, + userspace_dep); + } } } } @@ -598,10 +611,12 @@ bail: * Returns: 0 on success, negative on failure */ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, - struct ipa_rm_resource *depends_on) + struct ipa_rm_resource *depends_on, + bool userspace_dep) { int result = 0; int consumer_result; + bool add_dep_by_userspace; if (!resource || !depends_on) { IPA_RM_ERR("invalid params\n"); @@ -611,13 +626,17 @@ int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, if (ipa_rm_peers_list_check_dependency(resource->peers_list, resource->name, depends_on->peers_list, - depends_on->name)) { - IPA_RM_ERR("dependency already exists\n"); + depends_on->name, + &add_dep_by_userspace)) { + IPA_RM_ERR("dependency already exists, added by %s\n", + add_dep_by_userspace ? "userspace" : "kernel"); return -EEXIST; } - ipa_rm_peers_list_add_peer(resource->peers_list, depends_on); - ipa_rm_peers_list_add_peer(depends_on->peers_list, resource); + ipa_rm_peers_list_add_peer(resource->peers_list, depends_on, + userspace_dep); + ipa_rm_peers_list_add_peer(depends_on->peers_list, resource, + userspace_dep); IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); @@ -671,12 +690,14 @@ bail: * will be sent to the RM client */ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, - struct ipa_rm_resource *depends_on) + struct ipa_rm_resource *depends_on, + bool userspace_dep) { int result = 0; bool state_changed = false; bool release_consumer = false; enum ipa_rm_event evt; + bool add_dep_by_userspace; if (!resource || !depends_on) { IPA_RM_ERR("invalid params\n"); @@ -686,10 +707,24 @@ int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, if (!ipa_rm_peers_list_check_dependency(resource->peers_list, resource->name, depends_on->peers_list, - depends_on->name)) { + depends_on->name, + &add_dep_by_userspace)) { IPA_RM_ERR("dependency does not exist\n"); return -EINVAL; } + + /* + * to avoid race conditions between kernel and userspace + * need to check that the dependency was added by same entity + */ + if (add_dep_by_userspace != userspace_dep) { + IPA_RM_DBG("dependency was added by %s\n", + add_dep_by_userspace ? "userspace" : "kernel"); + IPA_RM_DBG("ignore request to delete dependency by %s\n", + userspace_dep ? "userspace" : "kernel"); + return 0; + } + IPA_RM_DBG("%s state: %d\n", ipa_rm_resource_str(resource->name), resource->state); diff --git a/drivers/platform/msm/ipa/ipa_rm_resource.h b/drivers/platform/msm/ipa/ipa_rm_resource.h index 26573e243b4e..5c3a0190753f 100644 --- a/drivers/platform/msm/ipa/ipa_rm_resource.h +++ b/drivers/platform/msm/ipa/ipa_rm_resource.h @@ -116,10 +116,12 @@ int ipa_rm_resource_producer_deregister(struct ipa_rm_resource_prod *producer, struct ipa_rm_register_params *reg_params); int ipa_rm_resource_add_dependency(struct ipa_rm_resource *resource, - struct ipa_rm_resource *depends_on); + struct ipa_rm_resource *depends_on, + bool userspace_dep); int ipa_rm_resource_delete_dependency(struct ipa_rm_resource *resource, - struct ipa_rm_resource *depends_on); + struct ipa_rm_resource *depends_on, + bool userspace_dep); int ipa_rm_resource_producer_request(struct ipa_rm_resource_prod *producer); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index ae9e2b5a109d..1f9fd7a38a37 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -1116,8 +1116,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - retval = ipa_rm_add_dependency(rm_depend.resource_name, - rm_depend.depends_on_name); + retval = ipa_rm_add_dependency_from_ioctl( + rm_depend.resource_name, rm_depend.depends_on_name); break; case IPA_IOC_RM_DEL_DEPENDENCY: if (copy_from_user((u8 *)&rm_depend, (u8 *)arg, @@ -1125,8 +1125,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - retval = ipa_rm_delete_dependency(rm_depend.resource_name, - rm_depend.depends_on_name); + retval = ipa_rm_delete_dependency_from_ioctl( + rm_depend.resource_name, rm_depend.depends_on_name); break; case IPA_IOC_GENERATE_FLT_EQ: { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 7acf07acb8c1..747ae3d82b68 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -1196,8 +1196,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - retval = ipa_rm_add_dependency(rm_depend.resource_name, - rm_depend.depends_on_name); + retval = ipa_rm_add_dependency_from_ioctl( + rm_depend.resource_name, rm_depend.depends_on_name); break; case IPA_IOC_RM_DEL_DEPENDENCY: if (copy_from_user((u8 *)&rm_depend, (u8 *)arg, @@ -1205,8 +1205,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - retval = ipa_rm_delete_dependency(rm_depend.resource_name, - rm_depend.depends_on_name); + retval = ipa_rm_delete_dependency_from_ioctl( + rm_depend.resource_name, rm_depend.depends_on_name); break; case IPA_IOC_GENERATE_FLT_EQ: { |
