Re: Possible memory leak in xfrm_policy_insert

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Jun 11, 2003 at 10:02:14AM +1000, herbert wrote:
> 
> I've got a better idea.  We can make flow_cache_flush take out all
> out-of-date entries as determined by genid.  I'll code it tonight.

Here is the patch with the objectless flow_cache_flush plus the
percpu stuff.
-- 
Debian GNU/Linux 3.0 is out! ( http://www.debian.org/ )
Email:  Herbert Xu ~{PmV>HI~} <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Index: kernel-source-2.5/include/net/flow.h
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/include/net/flow.h,v
retrieving revision 1.2
diff -u -r1.2 flow.h
--- kernel-source-2.5/include/net/flow.h	10 Jun 2003 09:19:10 -0000	1.2
+++ kernel-source-2.5/include/net/flow.h	11 Jun 2003 08:32:39 -0000
@@ -87,7 +87,7 @@
 
 extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
 			       flow_resolve_t resolver);
-extern void flow_cache_flush(void *object);
+extern void flow_cache_flush(void);
 extern atomic_t flow_cache_genid;
 
 #endif
Index: kernel-source-2.5/net/core/flow.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/core/flow.c,v
retrieving revision 1.4
diff -u -r1.4 flow.c
--- kernel-source-2.5/net/core/flow.c	10 Jun 2003 09:19:17 -0000	1.4
+++ kernel-source-2.5/net/core/flow.c	11 Jun 2003 08:53:58 -0000
@@ -15,6 +15,9 @@
 #include <linux/interrupt.h>
 #include <linux/smp.h>
 #include <linux/completion.h>
+#include <linux/percpu.h>
+#include <linux/bitops.h>
+#include <linux/notifier.h>
 #include <net/flow.h>
 #include <asm/atomic.h>
 #include <asm/semaphore.h>
@@ -54,12 +57,13 @@
 #define FLOW_HASH_RND_PERIOD	(10 * 60 * HZ)
 
 struct flow_flush_info {
-	void *object;
 	atomic_t cpuleft;
+	unsigned long cpumap;
 	struct completion completion;
 };
-static struct tasklet_struct flow_flush_tasklets[NR_CPUS];
-static DECLARE_MUTEX(flow_flush_sem);
+static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklet) = { NULL };
+
+static unsigned long flow_cache_cpu_map;
 
 static void flow_cache_new_hashrnd(unsigned long arg)
 {
@@ -182,7 +186,7 @@
 		}
 	}
 
-	if (!fle) {
+	if (!fle && test_bit(cpu, &flow_cache_cpu_map)) {
 		if (flow_count(cpu) > flow_hwm)
 			flow_cache_shrink(cpu);
 
@@ -224,18 +228,20 @@
 static void flow_cache_flush_tasklet(unsigned long data)
 {
 	struct flow_flush_info *info = (void *)data;
-	void *object = info->object;
 	int i;
 	int cpu;
 
 	cpu = smp_processor_id();
 	for (i = 0; i < flow_hash_size; i++) {
-		struct flow_cache_entry *fle, **flp;
+		struct flow_cache_entry *fle;
+
+		fle = flow_table[(cpu << flow_hash_shift) + i];
+		for (; fle; fle = fle->next) {
+			unsigned genid = atomic_read(&flow_cache_genid);
 
-		flp = &flow_table[(cpu << flow_hash_shift) + i];
-		for (; (fle = *flp) != NULL; flp = &fle->next) {
-			if (fle->object != object)
+			if (!fle->object || fle->genid == genid)
 				continue;
+
 			fle->object = NULL;
 			atomic_dec(fle->object_ref);
 		}
@@ -252,23 +258,27 @@
 	struct tasklet_struct *tasklet;
 
 	cpu = smp_processor_id();
-	tasklet = &flow_flush_tasklets[cpu];
-	tasklet_init(tasklet, flow_cache_flush_tasklet, (unsigned long)info);
+	if (!test_bit(cpu, &info->cpumap))
+		return;
+
+	tasklet = &per_cpu(flow_flush_tasklet, cpu);
+	tasklet->data = (unsigned long)info;
 	tasklet_schedule(tasklet);
 }
 
-void flow_cache_flush(void *object)
+void flow_cache_flush(void)
 {
 	struct flow_flush_info info;
+	static DECLARE_MUTEX(flow_flush_sem);
 
-	info.object = object;
-	atomic_set(&info.cpuleft, num_online_cpus());
+	info.cpumap = flow_cache_cpu_map;
+	atomic_set(&info.cpuleft, hweight32(info.cpumap));
 	init_completion(&info.completion);
 
 	down(&flow_flush_sem);
 
-	smp_call_function(flow_cache_flush_per_cpu, &info, 1, 0);
 	local_bh_disable();
+	smp_call_function(flow_cache_flush_per_cpu, &info, 1, 0);
 	flow_cache_flush_per_cpu(&info);
 	local_bh_enable();
 
@@ -277,6 +287,32 @@
 	up(&flow_flush_sem);
 }
 
+static void __devinit flow_cache_cpu_online(int cpu)
+{
+	struct tasklet_struct *tasklet;
+
+	tasklet = &per_cpu(flow_flush_tasklet, cpu);
+	tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
+
+	set_bit(cpu, &flow_cache_cpu_map);
+}
+
+static int __devinit flow_cache_cpu_notify(struct notifier_block *self,
+					   unsigned long action, void *hcpu)
+{
+	unsigned long cpu = (unsigned long)cpu;
+	switch (action) {
+	case CPU_UP_PREPARE:
+		flow_cache_cpu_online(cpu);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata flow_cache_cpu_nb = {
+	.notifier_call = flow_cache_cpu_notify,
+};
+
 static int __init flow_cache_init(void)
 {
 	unsigned long order;
@@ -315,6 +351,9 @@
 		panic("Failed to allocate flow cache hash table\n");
 
 	memset(flow_table, 0, PAGE_SIZE << order);
+
+	flow_cache_cpu_online(smp_processor_id());
+	register_cpu_notifier(&flow_cache_cpu_nb);
 
 	return 0;
 }
Index: kernel-source-2.5/net/xfrm/xfrm_policy.c
===================================================================
RCS file: /home/gondolin/herbert/src/CVS/debian/kernel-source-2.5/net/xfrm/xfrm_policy.c,v
retrieving revision 1.6
diff -u -r1.6 xfrm_policy.c
--- kernel-source-2.5/net/xfrm/xfrm_policy.c	10 Jun 2003 09:19:24 -0000	1.6
+++ kernel-source-2.5/net/xfrm/xfrm_policy.c	11 Jun 2003 08:32:47 -0000
@@ -214,7 +214,7 @@
 		atomic_dec(&policy->refcnt);
 
 	if (atomic_read(&policy->refcnt) > 1)
-		flow_cache_flush(policy);
+		flow_cache_flush();
 
 	xfrm_pol_put(policy);
 }

[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux 802.1Q VLAN]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Git]     [Bugtraq]     [Yosemite News and Information]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux PCI]     [Linux Admin]     [Samba]

  Powered by Linux