在linux的内核模块中要申请内存,一般都是使用kmalloc的方式申请一块指定大小的内存,但这个函数有一定的限制,一般只能申请到几M到十几M的内存空间,申请内存太多将会失败。这样的限制是好的,保证具有完全权限的内核程序不会无意地过度浪费内存资源(例如通过变量a进行kmalloc(a),但因为程序员的问题,导致a是一个非常大的数字,如果不限制就会因为内存不足就导致内核崩溃了。),如果要进行DMA操作,使用几M的内存已经能达到很好的效率。
但是肯定有在内核中使用超大块内存的情况,例如vmware,它可以预分配虚拟机的所有内存。这时候,就应该自己去按页分配并自己进行页管理。
这里有一个我以前写的内核中大型内存数组管理函数,提供给大家参考参考。没有写太多的注释,仅供有兴趣的参考哈
kvector.h
#ifndef _HOVERLEES_KVECTOR_H
#define _HOVERLEES_KVECTOR_H
#include
#define ELEMENT_LENGTH8
#define INDEX_LINK_EACH_NUM (PAGE_SIZE/sizeof(void*)-1)
#define ELEMENTS_PER_PAGE PAGE_SIZE/ELEMENT_LENGTH
typedef struct _index_link_node{
void* data_pages[INDEX_LINK_EACH_NUM];
struct _index_link_node * next;
}index_link_node;
typedef struct _kvector{
int size;
int current_index_pos;
int total_index_elements;
int index_node_num;
index_link_node* index;
}kvector;
typedef int (*KVECTOR_EACH_PAGE_CB)(void* p,void* param);
/*初始化数组*/
int kvector_init(kvector* vector,int init_size);
/*销毁数组*/
void kvector_destroy(kvector* vector);
/*数组大小更改*/
int kvector_resize(kvector* vector,int new_size);
/*设置数组中的第index个元素*/
int kvector_set(kvector* vector,int index,void* mem);
/*取得数组中的第index个元素*/
int kvector_get(kvector* vector,int index,void* mem);
void kvector_foreach_page(kvector* vector,KVECTOR_EACH_PAGE_CB callback,void* param);
#endif
kvector.c
#include "kvector.h"
void kvector_destroy(kvector* vector);
void* kvector_get_free_page(void){
void* r=(void*) get_zeroed_page(GFP_KERNEL);
return r;
}
void kvector_free_page(void* p){
free_page((unsigned long)p);
}
int kvector_index_add_link_node(kvector* vector){
index_link_node* p;
index_link_node* r=(index_link_node*)kvector_get_free_page();
if(!r) return 0;
r->next=NULL;
if(vector->index==NULL){
vector->index=r;
}
else{
p=vector->index;
while(p->next!=NULL){
p=p->next;
}
p->next=r;
}
vector->total_index_elements+=INDEX_LINK_EACH_NUM;
vector->index_node_num++;
return 1;
}
int kvector_add_data_page(kvector* vector){
index_link_node* node;
int r,i;
void* page;
int cpage=vector->current_index_pos/INDEX_LINK_EACH_NUM;
if(vector->current_index_pos>=vector->total_index_elements){
r=kvector_index_add_link_node(vector);
if(!r) return 0;
}
page=kvector_get_free_page();
if(!page) return 0;
node=vector->index;
for(i=0;i
node=node->next;
}
i=vector->current_index_pos%INDEX_LINK_EACH_NUM;
node->data_pages[i]=page;
vector->current_index_pos++;
return 1;
}
int kvector_init(kvector* vector,int init_size){
int r;
int i;
int init_page_num;
init_page_num=init_size/(ELEMENTS_PER_PAGE)+(init_size%(ELEMENTS_PER_PAGE)==0 ? 0:1);
vector->size=init_size;
vector->current_index_pos=0;
vector->total_index_elements=0;
vector->index_node_num=0;
vector->index=NULL;
for(i=0;i
r=kvector_add_data_page(vector);
if(!r){
kvector_destroy(vector);
return 0;
}
}
return 1;
}
int kvector_resize(kvector* vector,int new_size){
int add_page_num;
int i,r;
if(new_sizesize) return vector->size;
add_page_num=(new_size/(ELEMENTS_PER_PAGE)+(new_size%(ELEMENTS_PER_PAGE)==0 ? 0:1))-vector->current_index_pos;
for(i=0;i
r=kvector_add_data_page(vector);
if(!r){
return vector->size;
}
vector->size+=(ELEMENTS_PER_PAGE);
}
return vector->size;
}
void kvector_destroy(kvector* vector){
index_link_node *node,*t;
int i,j;
i=0;
node=vector->index;
while(node!=NULL){
for(j=0;j
if(i>=vector->current_index_pos) break;
kvector_free_page(node->data_pages[j]);
i++;
}
t=node;
node=node->next;
kvector_free_page(t);
}
}
void kvector_foreach_page(kvector* vector,KVECTOR_EACH_PAGE_CB callback,void* param){
index_link_node *node;
int i,j;
i=0;
node=vector->index;
while(node!=NULL){
for(j=0;j
if(i>=vector->current_index_pos) break;
if(!callback(node->data_pages[j],param)) return;
i++;
}
node=node->next;
}
}
int kvector_set(kvector* vector,int index,void* mem){
index_link_node* node;
int page_index;
int page_mem_index;
int node_index;
int node_page_index;
char* page_mem;
int i;
if(index>vector->size) return 0;
page_index=index/(ELEMENTS_PER_PAGE);
page_mem_index=index%(ELEMENTS_PER_PAGE);
node_index=page_index/INDEX_LINK_EACH_NUM;
node_page_index=page_index%INDEX_LINK_EACH_NUM;
node=vector->index;
for(i=0;i
node=node->next;
}
page_mem=(char*)node->data_pages[node_page_index];
page_mem+=(page_mem_index*ELEMENT_LENGTH);
memcpy(page_mem,mem,ELEMENT_LENGTH);
return 1;
}
int kvector_get(kvector* vector,int index,void* mem){
index_link_node* node;
int page_index;
int page_mem_index;
int node_index;
int node_page_index;
char* page_mem;
int i;
if(index>vector->size) return 0;
page_index=index/(ELEMENTS_PER_PAGE);
page_mem_index=index%(ELEMENTS_PER_PAGE);
node_index=page_index/INDEX_LINK_EACH_NUM;
node_page_index=page_index%INDEX_LINK_EACH_NUM;
node=vector->index;
for(i=0;i
node=node->next;
}
page_mem=(char*)node->data_pages[node_page_index];
page_mem+=(page_mem_index*ELEMENT_LENGTH);
memcpy(mem,page_mem,ELEMENT_LENGTH);
return 1;
}