Linux内核之虚拟内存区域页分配:alloc_pages_vma用法实例(六十四)

简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!

优质专栏:Audio工程师进阶系列原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课原创干货持续更新中……】🚀

人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.

更多原创,欢迎关注:Android系统攻城狮

欢迎关注Android系统攻城狮

🍉🍉🍉文章目录🍉🍉🍉

    • 🌻1.前言
    • 🌻2.Linux内核之alloc_pages_vma介绍
    • 🌻3.代码实例
      • 🐓3.1 内存映射设备驱动
      • 🐓3.2 分页内存分配设备驱动
      • 🐓3.3 大页内存分配设备驱动

🌻1.前言

本篇目的:Linux内核之虚拟内存区域页分配:alloc_pages_vma用法实例

🌻2.Linux内核之alloc_pages_vma介绍

  • alloc_pages_vma() 是Linux内核中用于在给定虚拟内存区域(VMA)中分配内存页面的函数。在操作系统中,内存管理是一个关键的任务,而分配内存页是其中的一项基本操作。该函数的作用是为进程或内核的特定需求在虚拟地址空间中动态分配连续的物理内存页,并返回一个指向分配内存页描述符的指针。

  • 在Linux内核中,虚拟内存区域(VMA)是一种用来管理进程虚拟地址空间的数据结构。每个进程都有一组VMA,用于描述其虚拟地址空间的布局。alloc_pages_vma() 函数的核心功能是在指定的VMA中分配内存页。通过该函数,可以实现各种内核操作,如文件系统、设备驱动程序等对内存的管理和操作。

  • 这个函数的原型如下:

Copy code
struct page *alloc_pages_vma(gfp_t gfp_mask, int order, struct vm_area_struct *vma, unsigned long addr, bool hugepage)
  • 参数说明:

gfp_mask:用于指定内存分配的行为标志,例如内存分配的优先级、是否可以睡眠等。
order:表示需要分配的页数,因为内存分配是按页进行的,所以 order 指定了需要分配的连续页数为 2^order 个。
vma:表示在哪个VMA中分配内存。
addr:表示希望内存分配的虚拟地址。
hugepage:表示是否尝试分配大页面。
alloc_pages_vma() 函数根据参数指定的条件,在指定的VMA中动态分配内存页。如果内存分配成功,则返回一个指向分配的页面描述符的指针;如果无法分配所需数量的页面,则返回 NULL。

  • 该函数常用于Linux内核中各种场景,如文件系统读写、网络数据包处理、设备驱动程序等,用于动态分配内存以存储数据或临时缓冲区。通过合理的调用和使用 alloc_pages_vma() 函数,可以实现高效的内存管理,确保系统运行的稳定性和性能。

🌻3.代码实例

🐓3.1 内存映射设备驱动

这个驱动允许用户空间程序将一个文件映射到内核空间,并使用alloc_pages_vma()在VMA中分配内存页来处理读写操作。

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>
#include <linux/mm.h>

#define DEVICE_NAME "memory_mapping_driver"
#define BUF_SIZE    PAGE_SIZE

static char *buffer;

// 打开设备
static int memory_mapping_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Memory Mapping Driver: 设备已打开\n");
    // 分配页
    buffer = (char *)alloc_pages_vma(GFP_KERNEL, get_order(BUF_SIZE), file->f_mapping->host, 0, false);
    if (!buffer) {
        printk(KERN_ALERT "Memory Mapping Driver: 内存分配失败\n");
        return -ENOMEM;
    }
    return 0;
}

// 内存映射
static int memory_mapping_mmap(struct file *file, struct vm_area_struct *vma) {
    unsigned long size = vma->vm_end - vma->vm_start;
    unsigned long pfn = virt_to_phys(buffer) >> PAGE_SHIFT;
    
    if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) {
        printk(KERN_ALERT "Memory Mapping Driver: 内存映射失败\n");
        return -EAGAIN;
    }
    return 0;
}

// 关闭设备
static int memory_mapping_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Memory Mapping Driver: 设备已关闭\n");
    // 释放页
    free_pages((unsigned long)buffer, get_order(BUF_SIZE));
    return 0;
}

static struct file_operations fops = {
    .open = memory_mapping_open,
    .mmap = memory_mapping_mmap,
    .release = memory_mapping_release,
};

static int __init memory_mapping_init(void) {
    printk(KERN_INFO "Memory Mapping Driver: 初始化驱动程序\n");
    if (register_chrdev(0, DEVICE_NAME, &fops) < 0) {
        printk(KERN_ALERT "Memory Mapping Driver: 注册设备失败\n");
        return -EFAULT;
    }
    return 0;
}

static void __exit memory_mapping_exit(void) {
    unregister_chrdev(0, DEVICE_NAME);
    printk(KERN_INFO "Memory Mapping Driver: 退出驱动程序\n");
}

module_init(memory_mapping_init);
module_exit(memory_mapping_exit);

MODULE_LICENSE("GPL");


🐓3.2 分页内存分配设备驱动

提供一个字符设备,允许用户空间程序以页为单位分配和释放内核空间中的内存。

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "page_allocation_driver"
#define PAGE_COUNT 4
#define BUF_SIZE   (PAGE_SIZE * PAGE_COUNT)

static char *buffer;

// 打开设备
static int page_allocation_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Page Allocation Driver: 设备已打开\n");
    // 分配页
    buffer = (char *)alloc_pages_vma(GFP_KERNEL, get_order(BUF_SIZE), NULL, 0, false);
    if (!buffer) {
        printk(KERN_ALERT "Page Allocation Driver: 内存分配失败\n");
        return -ENOMEM;
    }
    return 0;
}

// 读取设备
static ssize_t page_allocation_read(struct file *file, char __user *buf, size_t count, loff_t *offset) {
    if (copy_to_user(buf, buffer, count))
        return -EFAULT;
    return count;
}

// 关闭设备
static int page_allocation_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Page Allocation Driver: 设备已关闭\n");
    // 释放页
    free_pages((unsigned long)buffer, get_order(BUF_SIZE));
    return 0;
}

static struct file_operations fops = {
    .open = page_allocation_open,
    .read = page_allocation_read,
    .release = page_allocation_release,
};

static int __init page_allocation_init(void) {
    printk(KERN_INFO "Page Allocation Driver: 初始化驱动程序\n");
    if (register_chrdev(0, DEVICE_NAME, &fops) < 0) {
        printk(KERN_ALERT "Page Allocation Driver: 注册设备失败\n");
        return -EFAULT;
    }
    return 0;
}

static void __exit page_allocation_exit(void) {
    unregister_chrdev(0, DEVICE_NAME);
    printk(KERN_INFO "Page Allocation Driver: 退出驱动程序\n");
}

module_init(page_allocation_init);
module_exit(page_allocation_exit);

MODULE_LICENSE("GPL");;

🐓3.3 大页内存分配设备驱动

允许用户空间程序使用大页内存来进行高性能的数据处理,通过alloc_pages_vma()函数分配大页内存。

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/uaccess.h>

#define DEVICE_NAME "hugepage_allocation_driver"
#define BUF_SIZE    (2 * PAGE_SIZE)

static char *buffer;

// 打开设备
static int hugepage_allocation_open(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Hugepage Allocation Driver: 设备已打开\n");
    // 分配大页
    buffer = (char *)alloc_pages_vma(GFP_KERNEL, 1, NULL, 0, true);
    if (!buffer) {
        printk(KERN_ALERT "Hugepage Allocation Driver: 内存分配失败\n");
        return -ENOMEM;
    }
    return 0;
}

// 读取设备
static ssize_t hugepage_allocation_read(struct file *file, char __user *buf, size_t count, loff_t *offset) {
    if (copy_to_user(buf, buffer, count))
        return -EFAULT;
    return count;
}

// 关闭设备
static int hugepage_allocation_release(struct inode *inode, struct file *file) {
    printk(KERN_INFO "Hugepage Allocation Driver: 设备已关闭\n");
    // 释放大页
    free_pages((unsigned long)buffer, 1);
    return 0;
}

static struct file_operations fops = {
    .open = hugepage_allocation_open,
    .read = hugepage_allocation_read,
    .release = hugepage_allocation_release,
};

static int __init hugepage_allocation_init(void) {
    printk(KERN_INFO "Hugepage Allocation Driver: 初始化驱动程序\n");
    if (register_chrdev(0, DEVICE_NAME, &fops) < 0) {
        printk(KERN_ALERT "Hugepage Allocation Driver: 注册设备失败\n");
        return -EFAULT;
    }
    return 0;
}

static void __exit hugepage_allocation_exit(void) {
    unregister_chrdev(0, DEVICE_NAME);
    printk(KERN_INFO "Hugepage Allocation Driver: 退出驱动程序\n");
}

module_init(hugepage_allocation_init);
module_exit(hugepage_allocation_exit

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/587187.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

ESP32 和 Arduino 之间建立蓝牙连接

ESP32 和 Arduino Uno 可以通过蓝牙进行通信。为此&#xff0c;您必须使用与 Arduino 兼容的蓝牙模块。我们将使用 HC-05&#xff08;06&#xff09; 蓝牙模块。 连接Arduino Uno和HC-05蓝牙模块 将 HC-05 蓝牙模块连接到 Arduino 板。将模块的VCC、GND、RX、TX引脚连接到Ard…

1.4 Java全栈开发前端+后端(全栈工程师进阶之路)-前置课程java基础语法、java面向对象编程

Java核心语法&#xff1a; 对象&#xff1a;对象是类的一个实例&#xff08;对象不是找个女朋友&#xff09;&#xff0c;有状态和行为。例如&#xff0c;一条狗是一个对象&#xff0c;它的状态有&#xff1a;颜色、名字、品种&#xff1b;行为有&#xff1a;摇尾巴、叫、吃等。…

目前全球各类遥感卫星详细介绍

一、高分一号 高分一号&#xff08;GF-1&#xff09;是中国高分辨率对地观测系统重大专项&#xff08;简称高分专项&#xff09;的第一颗卫星。“高分专项”于2010年5月全面启动&#xff0c;计划到2020年建成中国自主的陆地、大气和海洋观测系统。 高分一号&#xff08;GF-1&…

Open Life Science AI (OLSA)

文章目录 关于 Open Life Science ![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/16d93b633c8442cc93ee6433ceea38e9.png 500x)关于 Open Life Science AI 关于 Open Life Science Open Life Science 是一个非营利组织。 官网&#xff1a; https://openlifesci…

实习面试算法准备之图论

这里写目录标题 1 基础内容1.1 图的表示1.2图的遍历 2 例题2.1 所有可能的路径2.2 课程表&#xff08;环检测算法&#xff09;2.2.1 环检测算法 DFS版2.2.2 环检测算法 BFS版 2.3 课程表 II &#xff08;拓扑排序算法&#xff09;2.3.1 拓扑排序 DFS版 1 基础内容 图没啥高深的…

【分布式通信】NPKit,NCCL的Profiling工具

NPKit介绍 NPKit (Networking Profiling Kit) is a profiling framework designed for popular collective communication libraries (CCLs), including Microsoft MSCCL, NVIDIA NCCL and AMD RCCL. It enables users to insert customized profiling events into different C…

Java项目:88 springboot104学生网上请假系统设计与实现

作者主页&#xff1a;舒克日记 简介&#xff1a;Java领域优质创作者、Java项目、学习资料、技术互助 文中获取源码 项目介绍 本学生网上请假系统管理员&#xff0c;教师&#xff0c;学生。 管理员功能有个人中心&#xff0c;学生管理&#xff0c;教师管理&#xff0c;班级信息…

程序员与土地的关系

目录 一、土地对人类的重要性 二、程序员与土地的关系 二、程序员如何利用GIS技术改变土地管理效率&#xff1f; 四、GIS技术有哪些运用&#xff1f; 五、shapely库计算多边形面积的例子 一、土地对人类的重要性 土地资源对人类是至关重要的。土地是人类赖…

力扣HOT100 - 131. 分割回文串

解题思路&#xff1a; class Solution {List<List<String>> res new ArrayList<>();List<String> pathnew ArrayList<>();public List<List<String>> partition(String s) {backtrack(s,0);return res;}public void backtrack(Str…

Windows下面源码安装PostgreSQL

目录 一、环境&#xff1a; 二、安装MSYS2 三、安装PG 四、初始化数据库 五、启停数据库 六、调试PG 平时我们在LINUX下&#xff0c;使用源码安装PG的比较多&#xff0c;但在WINDOWS下安装&#xff0c;一般是使用二机制安装包来安装&#xff0c;能否使用源码来安装呢&…

力扣82-链表、迭代 的思考

题目解读 给定一个已排序的链表的头 head &#xff0c; 删除原始链表中所有重复数字的节点&#xff0c;只留下不同的数字 。返回 已排序的链表 。 两个示范 思考 返回链表&#xff1a;返回更新链表后的头结点&#xff1b; 更新链表&#xff1a;判断重复元素&#xff0c;改变指针…

政府统计中如何使用大数据

当今世界&#xff0c;科技进步日新月异&#xff0c;互联网、云计算、大数据等现代信息技术深刻改变着人类的思维、生产、生活、学习方式。信息技术与经济社会的交汇融合引发了数据爆发式增长&#xff0c;数据已成为重要生产要素和国家基础性战略资源。近年来&#xff0c;国家统…

AI家居设备的未来:智能家庭的下一个大步

&#x1f512;目录 ☂️智能家居设备的发展和AI技术的作用 ❤️AI技术实现智能家居设备的自动化控制和智能化交互的依赖 AI家居设备的未来应用场景 &#x1f4a3;智能家庭在未来的发展和应用前景 &#x1f4a5;智能家居设备的发展和AI技术的作用 智能家居设备的发展和AI技术的…

【webrtc】MessageHandler 9: 基于线程的消息处理:执行Port销毁自己

Port::Port 构造的时候,就触发了一个异步操作,但是这个操作是要在 thread 里执行的,因此要通过post 消息 MSG_DESTROY_IF_DEAD 到thread跑:port的创建并米有要求在thread中 但是port的析构却在thread里 这是为啥呢?

【C# IO操作专题】

FileStream 是一个在多种编程语言中常见的概念&#xff0c;它代表了一个用于读写文件的流。在不同的编程语言中&#xff0c;FileStream 的实现和使用方式可能会有所不同&#xff0c;但基本概念是相似的&#xff1a;它允许程序以流的形式访问文件&#xff0c;即可以顺序地读取或…

二分图--判定以及最大匹配

水了个圈钱杯省一&#xff0c;不过估计国赛也拿不了奖&#xff0c;但还是小小挣扎一下。 什么是二分图&#xff1a;G(V,E)是一个无向图&#xff0c;若顶点V可以分为两个互不相交的子集A,B&#xff0c;并图中的每一条边&#xff08;i,j)所关联的ij属于不同的顶点集&#xff0c;…

2024 华东杯高校数学建模邀请赛(A题)| 比赛出场顺序 | 建模秘籍文章代码思路大全

铛铛&#xff01;小秘籍来咯&#xff01; 小秘籍团队独辟蹊径&#xff0c;以图匹配&#xff0c;多目标规划等强大工具&#xff0c;构建了这一题的详细解答哦&#xff01; 为大家量身打造创新解决方案。小秘籍团队&#xff0c;始终引领着建模问题求解的风潮。 抓紧小秘籍&#x…

24 JavaScript学习:this

this在对象方法中 在 JavaScript 中&#xff0c;this 的值取决于函数被调用的方式。在对象方法中&#xff0c;this 引用的是调用该方法的对象。 让我们看一个简单的例子&#xff1a; const person {firstName: John,lastName: Doe,fullName: function() {return this.firstN…

批处理优化

1.4、总结 Key的最佳实践 固定格式&#xff1a;[业务名]:[数据名]:[id]足够简短&#xff1a;不超过44字节不包含特殊字符 Value的最佳实践&#xff1a; 合理的拆分数据&#xff0c;拒绝BigKey选择合适数据结构Hash结构的entry数量不要超过1000设置合理的超时时间 2、批处理优…

cnPuTTY 0.81.0.1—PuTTY Release 0.81中文版本简单说明~~

2024-04-15 官方发布PuTTY 0.81本次发布主要修复了使用521位ECDSA密钥时的一个严重漏洞(CVE-2024-31497)。 如果您使用521位ECDSA私钥与任何早期版本的PuTTY组合&#xff0c;请考虑私钥已泄露的问题。强烈建议从相关文件中删除公钥&#xff0c;并使用新版本程序重新生成密钥对。…