Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 41dfdf84 authored by Conner Huff's avatar Conner Huff
Browse files

drivers: rmnet: perf: lock around deag



Locking around deagg protects us against
hotplug events where a core goes down for
thermal reasons. Without this, we could get
race conditions which lead to double free
problems. This also covers case where paged
data is used over linear data.

Change-Id: I1c2ee97cfb37c44c7f6d64446af0736e1c431eff
Signed-off-by: default avatarConner Huff <chuff@codeaurora.org>
parent d633c059
Loading
Loading
Loading
Loading
+19 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/jhash.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <net/ip6_checksum.h>
#include <net/tcp.h>
#include <net/udp.h>
@@ -111,6 +112,19 @@ MODULE_PARM_DESC(rmnet_perf_ingress_deag,

#define SHS_FLUSH 0

/* Lock around flow nodes for syncornization with rmnet_perf_opt_mode changes */
static DEFINE_SPINLOCK(rmnet_perf_core_lock);

void rmnet_perf_core_grab_lock(void)
{
	spin_lock_bh(&rmnet_perf_core_lock);
}

void rmnet_perf_core_release_lock(void)
{
	spin_unlock_bh(&rmnet_perf_core_lock);
}

/* rmnet_perf_core_set_ingress_hook() - sets appropriate ingress hook
 *		in the core rmnet driver
 *
@@ -751,6 +765,7 @@ void rmnet_perf_core_desc_entry(struct rmnet_frag_descriptor *frag_desc,
	u16 pkt_len = skb_frag_size(&frag_desc->frag);
	bool skip_hash = true;

	rmnet_perf_core_grab_lock();
	perf->rmnet_port = port;
	rmnet_perf_core_pre_ip_count++;
	memset(&pkt_info, 0, sizeof(pkt_info));
@@ -773,10 +788,12 @@ void rmnet_perf_core_desc_entry(struct rmnet_frag_descriptor *frag_desc,
	if (!rmnet_perf_opt_ingress(&pkt_info))
		goto flush;

	rmnet_perf_core_release_lock();
	return;

flush:
	rmnet_perf_core_flush_curr_pkt(&pkt_info, pkt_len, false, skip_hash);
	rmnet_perf_core_release_lock();
}

int __rmnet_perf_core_deaggregate(struct sk_buff *skb, struct rmnet_port *port)
@@ -899,6 +916,7 @@ void rmnet_perf_core_deaggregate(struct sk_buff *skb,

	perf = rmnet_perf_config_get_perf();
	perf->rmnet_port = port;
	rmnet_perf_core_grab_lock();
	while (skb) {
		struct sk_buff *skb_frag = skb_shinfo(skb)->frag_list;

@@ -930,4 +948,5 @@ void rmnet_perf_core_deaggregate(struct sk_buff *skb,

	rmnet_perf_core_pre_ip_count += co;
	rmnet_perf_core_chain_count[chain_count]++;
	rmnet_perf_core_release_lock();
}
+3 −0
Original line number Diff line number Diff line
@@ -131,6 +131,9 @@ enum rmnet_perf_trace_evt {
	RMNET_PERF_DEAG_PKT,
};


void rmnet_perf_core_grab_lock(void);
void rmnet_perf_core_release_lock(void);
void rmnet_perf_core_ps_on(void *port);
void rmnet_perf_core_ps_off(void *port);
bool rmnet_perf_core_is_deag_mode(void);
+4 −12
Original line number Diff line number Diff line
@@ -57,9 +57,6 @@ enum {
/* What protocols we optimize */
static int rmnet_perf_opt_mode = RMNET_PERF_OPT_MODE_ALL;

/* Lock around flow nodes for synchronization with rmnet_perf_opt_mode changes */
static DEFINE_SPINLOCK(rmnet_perf_opt_lock);

/* flow hash table */
DEFINE_HASHTABLE(rmnet_perf_opt_fht, RMNET_PERF_FLOW_HASH_TABLE_BITS);

@@ -78,7 +75,6 @@ static void rmnet_perf_opt_flush_flow_nodes_by_protocol(u8 protocol)
static int rmnet_perf_set_opt_mode(const char *val,
				   const struct kernel_param *kp)
{
	unsigned long ht_flags;
	int old_mode = rmnet_perf_opt_mode;
	int rc = -EINVAL;
	char value[4];
@@ -86,8 +82,7 @@ static int rmnet_perf_set_opt_mode(const char *val,
	strlcpy(value, val, 4);
	value[3] = '\0';

	local_bh_disable();
	spin_lock_irqsave(&rmnet_perf_opt_lock, ht_flags);
	rmnet_perf_core_grab_lock();

	if (!strcmp(value, "tcp"))
		rmnet_perf_opt_mode = RMNET_PERF_OPT_MODE_TCP;
@@ -123,8 +118,7 @@ static int rmnet_perf_set_opt_mode(const char *val,
	}

out:
	spin_unlock_irqrestore(&rmnet_perf_opt_lock, ht_flags);
	local_bh_enable();
	rmnet_perf_core_release_lock();

	return rc;
}
@@ -602,10 +596,10 @@ void rmnet_perf_opt_flush_all_flow_nodes(void)
 **/
void rmnet_perf_opt_chain_end(void)
{
	spin_lock(&rmnet_perf_opt_lock);
	rmnet_perf_core_grab_lock();
	rmnet_perf_opt_flush_reason_cnt[RMNET_PERF_OPT_CHAIN_END]++;
	rmnet_perf_opt_flush_all_flow_nodes();
	spin_unlock(&rmnet_perf_opt_lock);
	rmnet_perf_core_release_lock();
}

/* rmnet_perf_opt_insert_pkt_in_flow() - Inserts single IP packet into
@@ -701,7 +695,6 @@ bool rmnet_perf_opt_ingress(struct rmnet_perf_pkt_info *pkt_info)
	bool handled = false;
	bool flow_node_exists = false;

	spin_lock(&rmnet_perf_opt_lock);
	if (!rmnet_perf_optimize_protocol(pkt_info->trans_proto))
		goto out;

@@ -746,6 +739,5 @@ bool rmnet_perf_opt_ingress(struct rmnet_perf_pkt_info *pkt_info)
	}

out:
	spin_unlock(&rmnet_perf_opt_lock);
	return handled;
}