kmemdup函数功能描述:kmemdup( )函数的功能是根据给定的一段地址空间(这里由void * src
和size_t len
决定),再分配一个内存空间(分配模式是gfp),并将原地址空间中的内容拷贝到新分配的内存空间中。
kmemdup文件包含
#include<linux/string.h>
kmemdup函数定义
在内核源码中的位置:linux-3.19.3/mm/util.c
函数定义格式:
void *kmemdup(const void *src, size_t len, gfp_t gfp)
kmemdup输入参数说明
src
:给定的地址空间的起始地址。len
:要拷贝的原地址空间的长度。gfp
:分配模式,其取值及含义参考kmalloc( )函数的分析。
kmemdup返回参数说明
返回值为新分配的内存空间的起始地址,如果分配不成功则返回NULL。
kmemdup实例解析
编写测试文件:kmemdup.c
头文件及全局变量声明如下:
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
MODULE_LICENSE("GPL");
static int __init kmemdup_init(void);
static void __exit kmemdup_exit(void);
struct page * pages = NULL;
模块初始化函数:
int __init kmemdup_init(void)
{
pages = alloc_pages(GFP_KERNEL,0); //分配一个物理页,pages为指向该页的指针
if(! pages)
{
printk("alloc failed! \n");
return -ENOMEM;
}
else
{
char * temp = (char *)pages;
char x;
*temp = 'a';
int i = 0;
for(; i <26; i ++) //为分配的页进行循环赋值
{
x = *temp;
temp ++;
*temp = x+1;
}
/*调用函数,拷贝pages为起始地址的26个字符,分配模式为GFP_KERNEL */
char * addr = kmemdup( pages, 26, GFP_KERNEL);
printk("addr = 0x%lx\n", (unsigned long)addr); //输出所拷贝的目标起始地址
printk("*addr = %c\n", *addr); //输出第一个字符
printk("*addr+4 = %c\n", *(addr+4)); //输出第五个字符
for(temp = addr; *temp ! ='\0'; temp ++) //循环输出地址中的字符值
printk("%c", *temp);
printk("\n");
}
return 0;
}
模块退出函数:
void __exit kmemdup_exit(void)
{
if(pages)
__free_pages(pages,0); //释放由alloc_pages( )所分配的页。
printk("exit! \n");
}
模块初始化及退出函数调用:
module_init(kmemdup_init);
module_exit(kmemdup_exit);
实例运行结果及分析:
首先编译模块,执行命令insmod kmemdup.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。
结果分析:
在本测试程序中,首先分配一个物理页作为原内存空间,然后将其26字节空间填充字符值,填充完后依次为abcd…xyz
。之后我们调用kmemdup( )函数,参数值依次为pages、26、GFP_KERNEL,由字符型指针addr接收返回值。我们输出addr的值以及addr、addr+4的内容进行测试,由输出信息可知addr = 0xffff880145e831c0 ; *addr = a; *(addr + 4) = e
;最后再输出新内存空间26字节的内容(这里通过循环实现),输出值为abcd…xyz,这说明原地址空间的内容被拷贝到了新分配的内存空间中。最后由__free_pages( )函数释放原内存空间pages。