Linux内核模块vmalloc和kmalloc系统调用的代码实战

这篇具有很好参考价值的文章主要介绍了Linux内核模块vmalloc和kmalloc系统调用的代码实战。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、前言

当设备长时间运行后,内存碎片化,很难找到连续的物理页。在这种情况下,如果需要分配长度超过一页的内存块,可以使用不连续页分配器,分配虚拟地址连续但是物理地址不连续的内存块。在 32 位系统中不连分配器还有一个好处:优先从高端内存区域分配页,保留稀缺的低端内存区域。

二、编程接口

2.1、内核提供的vmalloc函数接口

  • vmalloc:分配不连续的物理地址空间,但虚拟内存地址是连续的。

  • vfree:配套,释放 vmalloc 分配的内存地址。

2.2、内核提供的kmalloc函数接口

  • kmalloc:分配物理连续的内存地址(则虚拟地址自然连续,基于 slab)。

  • kfree:配套,释放 kmalloc 分配的内存地址。

2.3、数据结构

struct vm_struct {
	struct vm_struct	*next;
	void			*addr;
	unsigned long		size;
	unsigned long		flags;
	struct page		**pages;
	unsigned int		nr_pages;
	phys_addr_t		phys_addr;
	const void		*caller;
};

struct vmap_area {
	unsigned long va_start;
	unsigned long va_end;

	struct rb_node rb_node;         /* address sorted rbtree */
	struct list_head list;          /* address sorted list */

	/*
	 * The following three variables can be packed, because
	 * a vmap_area object is always one of the three states:
	 *    1) in "free" tree (root is vmap_area_root)
	 *    2) in "busy" tree (root is free_vmap_area_root)
	 *    3) in purge list  (head is vmap_purge_list)
	 */
	union {
		unsigned long subtree_max_size; /* in "free" tree */
		struct vm_struct *vm;           /* in "busy" tree */
		struct llist_node purge_list;   /* in purge list */
	};
};
  • 每个虚拟内存区域对应一个 vmap_area 实例;
  • 每个 vmap_area 实例关联一个 vm_struct 实例;

三、vmalloc的使用示例

分配不连续的物理地址空间,但虚拟内存地址是连续的。

  1. 定义初始化模块和退出模块函数。
  2. 定义一个全局变量。
  3. 在初始化模块函数调用vmalloc函数,申请内存。
  4. 退出模块调用vfree释放内存。
  5. 模块初始化操作和退出函数调用module_init()和module_exit()。
  6. 其他的声明信息,比如许可协议、作者、模块功能描述等等。

vmtest.c

/* 头文件和全局变量地声明*/
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/module.h>

static int __init vmalloc_InitFunc(void);
static void __exit vmalloc_ExitFunc(void);

#define MEMORY_SIZE 4096
char * pmymemory;

// 模块初始化函数
int __init vmalloc_InitFunc(void)
{
    pmymemory = (char *)vmalloc(MEMORY_SIZE);
    if(pmymemory == NULL )
        printk("执行:vmalloc(...)函数分配内存失败! \n");
    else
        printk("执行:vmalloc(...)函数成功,地址 = 0x%lx\n", (unsigned long)pmymemory);
    return 0;
}

// 模块退出函数
void __exit vmalloc_ExitFunc(void)
{
    if(NULL != pmymemory)
    {
        vfree(pmymemory);
        printk("调用:vfree(...)释放内存成功!\n");
    }

    printk("正常:内核模块退出成功!\n");
}

/* 模块初始化操作和退出函数调用 */
module_init(vmalloc_InitFunc);
module_exit(vmalloc_ExitFunc);

MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lion Long"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : vmalloc/vfree"); /* 简要描述此模块用途及功能介绍*/

Makefile

obj-m:=vmtest.o	

CURRENT_PAHT:=$(shell pwd) 
LINUX_KERNEL:=$(shell uname -r)   

LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules

clean:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals

(1)make。

$ make
make -C /usr/src/linux-headers-4.15.0-142-generic    M=/home/fly/workspace/vmalloctest  modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
  CC [M]  /home/fly/workspace/vmalloctest/vmtest.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/fly/workspace/vmalloctest/vmtest.mod.o
  LD [M]  /home/fly/workspace/vmalloctest/vmtest.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

$ ls
Makefile  modules.order  Module.symvers  vmtest.c  vmtest.ko  vmtest.mod.c  vmtest.mod.o  vmtest.o

(2)插入模块。

# insmod vmtest.ko 
# dmesg -c
[159699.561428] 执行:vmalloc(...)函数成功,地址 = 0xffffa6aec0668000

四、kmalloc的使用示例

分配物理连续的内存地址(则虚拟地址自然连续,基于 slab)。

  1. 定义初始化模块和退出模块函数。
  2. 定义一个全局变量。
  3. 在初始化模块函数调用kmalloc函数,申请内存。
  4. 退出模块调用kfree释放内存。
  5. 模块初始化操作和退出函数调用module_init()和module_exit()。
  6. 其他的声明信息,比如许可协议、作者、模块功能描述等等。

kmtest.c

/* 头文件和全局变量地声明*/
#include <linux/vmalloc.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>

static int __init kmalloc_InitFunc(void);
static void __exit kmalloc_ExitFunc(void);

#define MEMORY_SIZE 4096
char * pmymemory;

// 模块初始化函数
int __init kmalloc_InitFunc(void)
{
    pmymemory = (char *)kmalloc(MEMORY_SIZE,GFP_KERNEL);
    if(pmymemory == NULL )
        printk("执行:kmalloc(...)函数分配内存失败! \n");
    else
    {
        // /*输出分配的内存空间的起始地址*/
        printk("执行:kmalloc(...)函数成功,地址 = 0x%lx\n", (unsigned long)pmymemory);
    }
        
    return 0;
}

// 模块退出函数
void __exit kmalloc_ExitFunc(void)
{
    if(NULL != pmymemory)
    {
        kfree(pmymemory);
        printk("调用:kfree(...)释放内存成功!\n");
    }

    printk("正常:内核模块退出成功!\n");
}

/* 模块初始化操作和退出函数调用 */
module_init(kmalloc_InitFunc);
module_exit(kmalloc_ExitFunc);

MODULE_LICENSE("GPL"); /* 描述模块代码接受的软件许可协议 */
MODULE_AUTHOR("Lingshengedu"); /* 描述模块的作者信息:包括作者姓名及邮箱等等 */
MODULE_DESCRIPTION(" kernel module : kmalloc/kfree"); /* 简要描述此模块用途及功能介绍*/

Makefile

obj-m:=kmkf.o	

CURRENT_PAHT:=$(shell pwd) 
LINUX_KERNEL:=$(shell uname -r)   

LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
all:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) modules

clean:

	make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PAHT) cleals

(1)make。

# make
make -C /usr/src/linux-headers-4.15.0-142-generic    M=/home/fly/workspace/kmalloctest  modules
make[1]: Entering directory '/usr/src/linux-headers-4.15.0-142-generic'
  CC [M]  /home/fly/workspace/kmalloctest/kmtest.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /home/fly/workspace/kmalloctest/kmtest.mod.o
  LD [M]  /home/fly/workspace/kmalloctest/kmtest.ko
make[1]: Leaving directory '/usr/src/linux-headers-4.15.0-142-generic'

# ls
kmtest.c  kmtest.ko  kmtest.mod.c  kmtest.mod.o  kmtest.o  Makefile  modules.order  Module.symvers

(2)insmod。

# insmod kmtest.ko 
# dmesg -c
[160514.302923] 执行:kmalloc(...)函数成功,地址 = 0xffff8f54b28ac000

Linux内核模块vmalloc和kmalloc系统调用的代码实战文章来源地址https://www.toymoban.com/news/detail-414731.html

到了这里,关于Linux内核模块vmalloc和kmalloc系统调用的代码实战的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux 内核源码分析笔记】系统调用

    在Linux内核中,系统调用是用户空间程序与内核之间的接口,它允许用户空间程序请求内核执行特权操作或访问受保护的内核资源。系统调用提供了一种安全可控的方式,使用户程序能够利用内核功能而不直接访问底层硬件。 系统调用: 通过系统调用,用户程序可以请求内核

    2024年02月03日
    浏览(45)
  • 【Linux C】Linux如何执行一个程序(程序存储空间、系统调用、内核调用)

    本节说的空间主要是指内存空间,即程序如何分配和使用内存。 可执行程序,而不是源代码。 C语言程序的存储空间包括以下几个主要部分: 代码段(Text Segment): 也称 正文段 , 代码段是存储C程序的机器代码的区域。它包含了程序的指令集,这些指令由编译器生成,并且

    2024年02月08日
    浏览(49)
  • 《Linux内核源码分析》(2)进程原理及系统调用

    操作系统的作用 :作为硬件的使用层,提供使用硬件资源的能力, 进程的作用 :作为操作系统使用层,提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别 :进程指计算机中已运行的程序。进程本身不是基本的运行单位,而是线程的容器。 程序本身只是指令

    2024年02月07日
    浏览(50)
  • 调试linux内核(2): poll系统调用的实现

    linux内核为用户态进程提供了一组IO相关的系统调用: select/poll/epoll, 这三个系统调用功能类似, 在使用方法和性能等方面存在一些差异. 使用它们, 用户态的进程可以\\\"监控\\\"自己感兴趣的文件描述符, 当这些文件描述符的状态发生改变时, 比如可读或者可写了, 内核会通知进程去处

    2024年02月11日
    浏览(36)
  • 杭电操作系统实验一 --- Linux内核编译及添加系统调用(arm架构华为云)

    掌握Linux 内核的编译与安装 掌握Linux 系统调用基本概念 设计和添加linux系统调用         (1)修改或返回指定进程的优先级(nice值和prio值)(详见教材P328)提示:可能参考的内核函数:set_user_nice().         (2)改变主机名称为自定义字符串(自选题目)   1、 L

    2023年04月20日
    浏览(44)
  • 操作系统实验 2.3系统调用:linux-0.11-lab “为版本0内核增加一个系统调用getjiffies” 和 “在用户程序中使用新增的系统调用”

    打开 vscode ,在如图所示位置打开 ~/os/linux-0.11-lab/0 文件夹 1.定义getjiffies系统调用 题目中给的提示:进入到 unistd.h 文件中 阅读代码,可以发现上图划线处有个系统调用名为 getpid :返回当前进程号——这与我们期望实现的功能类似:通过系统调用返回jiffies值。 于是此时希望

    2023年04月08日
    浏览(98)
  • 【Shell 命令集合 系统设置 】Linux 加载和卸载内核模块 modprobe命令 使用指南

    Shell 命令专栏:Linux Shell 命令全解析 modprobe命令是Linux系统中用于加载和卸载内核模块的工具。内核模块是一种可以动态加载到内核中的代码,它们可以扩展内核的功能,添加新的驱动程序或功能。 modprobe命令的主要作用有以下几个方面: 加载内核模块:modprobe命令可以根据

    2024年02月04日
    浏览(62)
  • 【Shell 命令集合 系统设置 】⭐Linux 向内核中加载指定的模块 insmod命令 使用指南

    Shell 命令专栏:Linux Shell 命令全解析 insmod命令是Linux系统中的一个命令,用于向内核中加载指定的模块。它的作用是将指定的模块文件加载到内核中,使得系统可以使用该模块提供的功能。 模块是一种可以动态加载到内核中的代码,它可以扩展内核的功能。在Linux系统中,模

    2024年02月07日
    浏览(58)
  • Linux 内核线程启动以及内核调用应用层程序

    #include linux/kthread.h //内核线程头文件   static task_struct *test_task; test_task = kthread_run(thread_function, NULL, \\\"test_thread_name\\\"); if(IS_ERR(test_task)) {         pr_err(\\\"test_thread_name create failn\\\"); } static int thread_function(void *arg) {     char *envp[3];     char *argv[3];     int ret= 0;     argv[0] = \\\"/bin/sh\\\";  

    2024年02月12日
    浏览(58)
  • Linux内核学习(十三)—— 设备与模块(基于Linux 2.6内核)

    目录 一、设备类型 二、模块 构建模块 安装模块 载入模块 在 Linux 以及 Unix 系统中,设备被分为以下三种类型: 块设备(blkdev) :以块为寻址单位,块的大小随设备的不同而变化;块设备通常支持重定位(seeking)操作,也就是对数据的随机访问。如硬盘、蓝光光碟和 Flas

    2024年02月11日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包