在linux的内核模块中要申请内存,一般都是使用kmalloc的方式申请一块指定大小的内存,但这个函数有一定的限制,一般只能申请到几M到十几M的内存空间,申请内存太多将会失败。这样的限制是好的,保证具有完全权限的内核程序不会无意地过度浪费内存资源(例如通过变量a进行kmalloc(a),但因为程序员的问题,导致a是一个非常大的数字,如果不限制就会因为内存不足就导致内核崩溃了。),如果要进行DMA操作,使用几M的内存已经能达到很好的效率。
但是肯定有在内核中使用超大块内存的情况,例如vmware,它可以预分配虚拟机的所有内存。这时候,就应该自己去按页分配并自己进行页管理。
这里有一个我以前写的内核中大型内存数组管理函数,提供给大家参考参考。没有写太多的注释,仅供有兴趣的参考哈
kvector.h
#ifndef _HOVERLEES_KVECTOR_H #define _HOVERLEES_KVECTOR_H #include <linux/slab.h> #define ELEMENT_LENGTH 8 #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<cpage;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<init_page_num;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_size<vector->size) 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<add_page_num;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<INDEX_LINK_EACH_NUM;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<INDEX_LINK_EACH_NUM;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_index;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_index;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; }