/*******************************************************************************************************************************************************/
/*******************************************************************************************************************************************************/
/*ļʵݰڴԱ׼linuxṩݰָ뼰عӿڣskbڴй¶ٴ*/
/*cacheƣҪģcacheskbʱinvalidͶݸⲿģֻDDRݣcacheݣҪѡˢcache*/
/*******************************************************************************************************************************************************/
/*******************************************************************************************************************************************************/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/kmemcheck.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#ifdef CONFIG_NET_CLS_ACT
#include <net/pkt_sched.h>
#endif
#include <linux/string.h>
#include <linux/skbuff.h>
#include <linux/splice.h>
#include <linux/cache.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
#include <linux/errqueue.h>
#include <linux/prefetch.h>
//#include <linux/psbuff.h>

#include <net/protocol.h>
#include <net/dst.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <net/xfrm.h>

#include <asm/uaccess.h>
#include <trace/events/skb.h>
#include "../kmap_skb.h"

#include <linux/wakelock.h>

//#include <linux/ext_mem.h>
#include <linux/hash.h>



//ⲿģصݰhashб
struct exthash_list toExt_hashlist[EXT2_MEM_HASH];

spinlock_t  toext_lock;




//ⲿģͷݰڴⲿģ鷢ݰַ׼linuxʱ,ṩⲿģдӿڴ
//ݰָ룬extҵӦĽڵ㣬ɾýڵ㣬skbָ
struct sk_buff * get_extnode_skb(void *data)
{
	struct extskb_info *temp = NULL;
	unsigned long spin_flag;
	struct sk_buff *skb_temp;

	spin_lock_irqsave(&toext_lock,spin_flag);
	data_page = get_page(data);//ȡdataӦpageַԴΪhashֵ
	list_for_each_entry(temp,&toExt_hashlist[data_page].first, node)
	{
		//䷶ΧҪ
		if(temp->info.skb ->datadataͬһݰΧ)
		{
			skb_temp = temp->info.skb;
			list_del(&temp->node);
			kfree(temp);
			spin_unlock_irqrestore(&toext_lock,spin_flag);
			return skb_temp;
		}
	}
	//CPָ룬ڴlogϢУ쳣
	panic("assert");
	spin_unlock_irqrestore(&toext_lock,spin_flag);
	return NULL;
}


//ⲿģʹõskb뵽hashڵУڱ׼linuxͶskb->dataⲿģʱҲҪøýӿ
void insert_toext_hash(struct sk_buff *skb)
{
	static int toext_init_num = 0;
	int i = 0;
	struct extskb_info *temp = NULL;
	struct exthash_list *head;
	unsigned long spin_flag;

	//Ϊ߿ܣhashʼʹõĵһʹ
	if(toext_init_num == 0) 
	{
	 	spin_lock_init(&toext_lock);
		for(i=0;i<EXT2_MEM_HASH;i++)
		{
			toExt_hashlist[i].count = 0;
			INIT_LIST_HEAD(&toExt_hashlist[i].first);
		}
	 	toext_init_num++;
	}	
	spin_lock_irqsave(&toext_lock,spin_flag);
	data_page = get_page(skb->data);//ȡdataӦpageַԴΪhashֵ
	head = &toExt_hashlist[addr_Hash(data_page)];
	temp = kmalloc(sizeof(struct extskb_info), GFP_ATOMIC);
	if(temp == NULL){
		panic("data err");}
	
	temp->info.skb = skb;
	
	list_add_tail(&temp->node, &head->first);
	head->count++;
	spin_unlock_irqrestore(&toext_lock,spin_flag);
	//printk("!!!!!!toCp_num=%d",toCp_num);
}

//ⲿģIPݰڴ棬ڲͨ׼linuxskbӿ룬Ӹٹ켣
//οnetdev_alloc_skbӿʵ֣Ҫȷdatagfp_maskĿǰ֧0
void *ext_alloc_data(int len, gfp_t gfp_mask)
{
	struct sk_buff *skb;
	int len;
	//˴ͷδԤݾƷ󣬿ԿԤͷϢ
	skb = __alloc_skb(len , GFP_KERNEL, 0, NUMA_NO_NODE);
	if (likely(skb)) {
		invalid_cache(skb->head,len);
		//ٹ켣Դfree_ext_memӿȷͷ
		insert_toext_hash(skb);
		skb->dev = NULL;
		return skb->data;
	}
	//˴Ƿʧܣpanic
	return NULL;
}

//ⲿģãͷݰַռʱãڲҵӦskbִskbͷ
int free_ext_mem(void *data)
{
	struct sk_buff *skb_temp;
	skb_temp = get_extnode_skb(data);
	kfree_skb((struct sk_buff *)skb);
	return 0;
}

















