All pastes #82228 Raw Edit

Miscellany

public text v1 · immutable
·published 2006-07-08 05:32 UTC
rendered paste body
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/list.h>
#include <linux/jhash.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/random.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/smp.h>
#include <linux/completion.h>
#include <linux/percpu.h>
#include <linux/bitops.h>
#include <linux/notifier.h>
#include <linux/cpu.h>
#include <linux/cpumask.h>
#include <net/flow.h>
#include <asm/atomic.h>
#include <asm/semaphore.h>

struct flow_cache_entry {
        struct flow_cache_entry *next;
        u16                     family;
        u8                      dir;
        struct flowi            key;
        u32                     genid;
        void                    *object;
        atomic_t                *object_ref;
};

static void flow_cache_shrink(int cpu)
{
        int shrink_to = flow_lwm / flow_hash_size;

        __flow_cache_shrink(cpu, shrink_to);
}

static void flow_new_hash_rnd(int cpu)
{
        get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32));
        flow_hash_rnd_recalc(cpu) = 0;

        __flow_cache_shrink(cpu, 0);
}

static u32 flow_hash_code(struct flowi *key, int cpu)
{
        u32 *k = (u32 *) key;

        return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) &
                (flow_hash_size - 1));
}

#if (BITS_PER_LONG == 64)
typedef u64 flow_compare_t;
#else
typedef u32 flow_compare_t;
#endif

extern void flowi_is_missized(void);

/* I hear what you're saying, use memcmp.  But memcmp cannot make
 * important assumptions that we can here, such as alignment and
 * constant size.
 */

static void __devinit flow_cache_cpu_prepare(int cpu)
{
        struct tasklet_struct *tasklet;
        unsigned long order;

        for (order = 0;
             (PAGE_SIZE << order) <
                     (sizeof(struct flow_cache_entry *)*flow_hash_size);
             order++)
                /* NOTHING */;

        flow_table(cpu) = (struct flow_cache_entry **)
                __get_free_pages(GFP_KERNEL, order);
        if (!flow_table(cpu))
                panic("NET: failed to allocate flow cache order %lu\n", order);

        memset(flow_table(cpu), 0, PAGE_SIZE << order);

        flow_hash_rnd_recalc(cpu) = 1;
        flow_count(cpu) = 0;

        tasklet = flow_flush_tasklet(cpu);
        tasklet_init(tasklet, flow_cache_flush_tasklet, 0);
}

static int __init flow_cache_init(void)
{
        int i;

        flow_cachep = kmem_cache_create("flow_cache",
                                        sizeof(struct flow_cache_entry),
                                        0, SLAB_HWCACHE_ALIGN,
                                        NULL, NULL);

        if (!flow_cachep)
                panic("NET: failed to allocate flow cache slab\n");

        flow_hash_shift = 10;
        flow_lwm = 2 * flow_hash_size;
        flow_hwm = 4 * flow_hash_size;

        init_timer(&flow_hash_rnd_timer);
        flow_hash_rnd_timer.function = flow_cache_new_hashrnd;
        flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
        add_timer(&flow_hash_rnd_timer);

        for_each_cpu(i)
                flow_cache_cpu_prepare(i);

        hotcpu_notifier(flow_cache_cpu, 0);
        return 0;
}