예제 #1
0
파일: vrf.c 프로젝트: a2hojsjsjs/linux
static void vrf_rtable_destroy(struct net_vrf *vrf)
{
	struct dst_entry *dst = (struct dst_entry *)vrf->rth;

	dst_destroy(dst);
	vrf->rth = NULL;
}
예제 #2
0
static void dst_run_gc(unsigned long dummy)
{
	int    delayed = 0;
	struct dst_entry * dst, **dstp;

	if (!spin_trylock(&dst_lock)) {
		mod_timer(&dst_gc_timer, jiffies + HZ/10);
		return;
	}


	del_timer(&dst_gc_timer);
	dstp = &dst_garbage_list;
	while ((dst = *dstp) != NULL) {
		if (atomic_read(&dst->__refcnt)) {
			dstp = &dst->next;
			delayed++;
			continue;
		}
		*dstp = dst->next;

		dst = dst_destroy(dst);
		if (dst) {
			/* NOHASH and still referenced. Unless it is already
			 * on gc list, invalidate it and add to gc list.
			 *
			 * Note: this is temporary. Actually, NOHASH dst's
			 * must be obsoleted when parent is obsoleted.
			 * But we do not have state "obsoleted, but
			 * referenced by parent", so it is right.
			 */
			if (dst->obsolete > 1)
				continue;

			___dst_free(dst);
			dst->next = *dstp;
			*dstp = dst;
			dstp = &dst->next;
		}
	}
	if (!dst_garbage_list) {
		dst_gc_timer_inc = DST_GC_MAX;
		goto out;
	}
	if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
		dst_gc_timer_expires = DST_GC_MAX;
	dst_gc_timer_inc += DST_GC_INC;
	dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
#if RT_CACHE_DEBUG >= 2
	printk("dst_total: %d/%d %ld\n",
	       atomic_read(&dst_total), delayed,  dst_gc_timer_expires);
#endif
	add_timer(&dst_gc_timer);

out:
	spin_unlock(&dst_lock);
}
예제 #3
0
void dst_release(struct dst_entry *dst)
{
	if (dst) {
		int newrefcnt;

		newrefcnt = atomic_dec_return(&dst->__refcnt);
		WARN_ON(newrefcnt < 0);
		if (unlikely(dst->flags & DST_NOCACHE) && !newrefcnt) {
			dst = dst_destroy(dst);
			if (dst)
				__dst_free(dst);
		}
	}
}
예제 #4
0
파일: vrf.c 프로젝트: a2hojsjsjs/linux
static int vrf_rt6_create(struct net_device *dev)
{
	struct net_vrf *vrf = netdev_priv(dev);
	struct dst_entry *dst;
	struct rt6_info *rt6;
	int cpu;
	int rc = -ENOMEM;

	rt6 = dst_alloc(&vrf_dst_ops6, dev, 0,
			DST_OBSOLETE_NONE,
			(DST_HOST | DST_NOPOLICY | DST_NOXFRM));
	if (!rt6)
		goto out;

	dst = &rt6->dst;

	rt6->rt6i_pcpu = alloc_percpu_gfp(struct rt6_info *, GFP_KERNEL);
	if (!rt6->rt6i_pcpu) {
		dst_destroy(dst);
		goto out;
	}
	for_each_possible_cpu(cpu) {
		struct rt6_info **p = per_cpu_ptr(rt6->rt6i_pcpu, cpu);
		*p =  NULL;
	}

	memset(dst + 1, 0, sizeof(*rt6) - sizeof(*dst));

	INIT_LIST_HEAD(&rt6->rt6i_siblings);
	INIT_LIST_HEAD(&rt6->rt6i_uncached);

	rt6->dst.input	= vrf_input6;
	rt6->dst.output	= vrf_output6;

	rt6->rt6i_table = fib6_get_table(dev_net(dev), vrf->tb_id);

	atomic_set(&rt6->dst.__refcnt, 2);

	vrf->rt6 = rt6;
	rc = 0;
out:
	return rc;
}
예제 #5
0
파일: dst.c 프로젝트: dmgerman/original
static void dst_run_gc(unsigned long dummy)
{
	int    delayed = 0;
	struct dst_entry * dst, **dstp;

	if (!spin_trylock(&dst_lock)) {
		mod_timer(&dst_gc_timer, jiffies + HZ/10);
		return;
	}


	del_timer(&dst_gc_timer);
	dstp = &dst_garbage_list;
	while ((dst = *dstp) != NULL) {
		if (atomic_read(&dst->__refcnt)) {
			dstp = &dst->next;
			delayed++;
			continue;
		}
		*dstp = dst->next;
		dst_destroy(dst);
	}
	if (!dst_garbage_list) {
		dst_gc_timer_inc = DST_GC_MAX;
		goto out;
	}
	if ((dst_gc_timer_expires += dst_gc_timer_inc) > DST_GC_MAX)
		dst_gc_timer_expires = DST_GC_MAX;
	dst_gc_timer_inc += DST_GC_INC;
	dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
#if RT_CACHE_DEBUG >= 2
	printk("dst_total: %d/%d %ld\n",
	       atomic_read(&dst_total), delayed,  dst_gc_timer_expires);
#endif
	add_timer(&dst_gc_timer);

out:
	spin_unlock(&dst_lock);
}
예제 #6
0
static void dst_gc_task(struct work_struct *work)
{
	int    delayed = 0;
	int    work_performed = 0;
	unsigned long expires = ~0L;
	struct dst_entry *dst, *next, head;
	struct dst_entry *last = &head;
#if RT_CACHE_DEBUG >= 2
	ktime_t time_start = ktime_get();
	struct timespec elapsed;
#endif

	mutex_lock(&dst_gc_mutex);
	next = dst_busy_list;

loop:
	while ((dst = next) != NULL) {
		next = dst->next;
		prefetch(&next->next);
		cond_resched();
		if (likely(atomic_read(&dst->__refcnt))) {
			last->next = dst;
			last = dst;
			delayed++;
			continue;
		}
		work_performed++;

		dst = dst_destroy(dst);
		if (dst) {
			/* NOHASH and still referenced. Unless it is already
			 * on gc list, invalidate it and add to gc list.
			 *
			 * Note: this is temporary. Actually, NOHASH dst's
			 * must be obsoleted when parent is obsoleted.
			 * But we do not have state "obsoleted, but
			 * referenced by parent", so it is right.
			 */
			if (dst->obsolete > 1)
				continue;

			___dst_free(dst);
			dst->next = next;
			next = dst;
		}
	}

	spin_lock_bh(&dst_garbage.lock);
	next = dst_garbage.list;
	if (next) {
		dst_garbage.list = NULL;
		spin_unlock_bh(&dst_garbage.lock);
		goto loop;
	}
	last->next = NULL;
	dst_busy_list = head.next;
	if (!dst_busy_list)
		dst_garbage.timer_inc = DST_GC_MAX;
	else {
		/*
		 * if we freed less than 1/10 of delayed entries,
		 * we can sleep longer.
		 */
		if (work_performed <= delayed/10) {
			dst_garbage.timer_expires += dst_garbage.timer_inc;
			if (dst_garbage.timer_expires > DST_GC_MAX)
				dst_garbage.timer_expires = DST_GC_MAX;
			dst_garbage.timer_inc += DST_GC_INC;
		} else {
			dst_garbage.timer_inc = DST_GC_INC;
			dst_garbage.timer_expires = DST_GC_MIN;
		}
		expires = dst_garbage.timer_expires;
		/*
		 * if the next desired timer is more than 4 seconds in the
		 * future then round the timer to whole seconds
		 */
		if (expires > 4*HZ)
			expires = round_jiffies_relative(expires);
		schedule_delayed_work(&dst_gc_work, expires);
	}

	spin_unlock_bh(&dst_garbage.lock);
	mutex_unlock(&dst_gc_mutex);
#if RT_CACHE_DEBUG >= 2
	elapsed = ktime_to_timespec(ktime_sub(ktime_get(), time_start));
	printk(KERN_DEBUG "dst_total: %d delayed: %d work_perf: %d"
		" expires: %lu elapsed: %lu us\n",
		atomic_read(&dst_total), delayed, work_performed,
		expires,
		elapsed.tv_sec * USEC_PER_SEC +
		  elapsed.tv_nsec / NSEC_PER_USEC);
#endif
}
예제 #7
0
파일: vrf.c 프로젝트: a2hojsjsjs/linux
static void vrf_rt6_destroy(struct net_vrf *vrf)
{
	dst_destroy(&vrf->rt6->dst);
	free_percpu(vrf->rt6->rt6i_pcpu);
	vrf->rt6 = NULL;
}