简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长!
优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀
优质专栏:多媒体系统工程师系列【原创干货持续更新中……】🚀
优质视频课程:AAOS车载系统+AOSP14系统攻城狮入门实战课【原创干货持续更新中……】🚀
人生格言: 人生从来没有捷径,只有行动才是治疗恐惧和懒惰的唯一良药.
🍉🍉🍉文章目录🍉🍉🍉
- 🌻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