dfc: fix spinlock leak

In the DFC powersave work, the separate spin lock and unlock
of multiple qos structures could be out of sync during SSR
and results in spinlock leak after exiting the work.

This change consolidated the spinlock operations to avoid
multiple locking and unlocking, and fixed below issue:

BUG: workqueue leaked lock or atomic: kworker/0:9/0x00000201/1361
     last function: qmi_rmnet_check_stats_2.cfi_jt [rmnet_core]
1 lock held by kworker/0:9/1361:
(&qos->qos_lock){....}-{2:2}, at: rmnet_lock_unlock_all_flows+0xa4/0xdc

Change-Id: I10c1687a4f9993363dc631dee0b347faaa1067ab
Acked-by: Weiyi Chen <weiyic@qti.qualcomm.com>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
This commit is contained in:
Subash Abhinov Kasiviswanathan
2021-08-17 20:21:55 -07:00
parent 6b6ee8b645
commit ef13a42ae2
4 changed files with 33 additions and 114 deletions

View File

@@ -755,24 +755,7 @@ out:
}
EXPORT_SYMBOL(rmnet_all_flows_enabled);
void rmnet_lock_unlock_all_flows(void *port, bool lock)
{
struct rmnet_endpoint *ep;
unsigned long bkt;
if (unlikely(!port))
return;
rcu_read_lock();
hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep,
bkt, ep, hlnode) {
qmi_rmnet_lock_unlock_all_flows(ep->egress_dev, lock);
}
rcu_read_unlock();
}
EXPORT_SYMBOL(rmnet_lock_unlock_all_flows);
void rmnet_get_disabled_flows(void *port, u8 *num_bearers, u8 *bearer_id)
void rmnet_prepare_ps_bearers(void *port, u8 *num_bearers, u8 *bearer_id)
{
struct rmnet_endpoint *ep;
unsigned long bkt;
@@ -789,7 +772,7 @@ void rmnet_get_disabled_flows(void *port, u8 *num_bearers, u8 *bearer_id)
hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep,
bkt, ep, hlnode) {
num_bearers_in_out = number_bearers_left;
qmi_rmnet_get_disabled_flows(ep->egress_dev,
qmi_rmnet_prepare_ps_bearers(ep->egress_dev,
&num_bearers_in_out,
bearer_id ? bearer_id +
current_num_bearers : NULL);
@@ -800,24 +783,7 @@ void rmnet_get_disabled_flows(void *port, u8 *num_bearers, u8 *bearer_id)
*num_bearers = current_num_bearers;
}
EXPORT_SYMBOL(rmnet_get_disabled_flows);
void rmnet_reset_enabled_flows(void *port)
{
struct rmnet_endpoint *ep;
unsigned long bkt;
if (unlikely(!port))
return;
rcu_read_lock();
hash_for_each_rcu(((struct rmnet_port *)port)->muxed_ep,
bkt, ep, hlnode) {
qmi_rmnet_reset_enabled_flows(ep->egress_dev);
}
rcu_read_unlock();
}
EXPORT_SYMBOL(rmnet_reset_enabled_flows);
EXPORT_SYMBOL(rmnet_prepare_ps_bearers);
int rmnet_get_powersave_notif(void *port)
{