free_contig_range()是alloc_contig_range()的配套释放函数,用于释放通过连续内存分配接口获得的页块。核心作用与背景前面讲过,alloc_contig_range()/alloc_contig_pages()通过隔离和迁移,从伙伴系统中“挖”出一段连续的物理内存。这些页在分配时是独立的单页(每页引用计数为 1,非复合页),因此不能用常规的free_pages()按阶数整体释放。free_contig_range()就是专门用来释放这类连续内存的:逐页释放。核心实现实现非常直接:/** * free_contig_range() - Free pages in a range * @pfn: The start pfn of the pages being freed. * @nr_pages: The number of pages being freed */ void free_contig_range(unsigned long pfn, unsigned long nr_pages) { unsigned long end = pfn + nr_pages; while (pfn < end) __free_page(pfn_to_page(pfn++)); } EXPORT_SYMBOL(free_contig_range);逐步解析1. 计算结束 PFNunsigned long end = pfn + nr_pages;把起始 PFN 和页数转换为[pfn, end)区间。2. 逐页释放while (pfn < end) __free_page(pfn_to_page(pfn++));遍历[pfn, end)中的每一页。对每页调用__free_page()(等价于__free_pages(page, 0)),作为order-0 单页释放回伙伴系统。每页的引用计数在分配时已被设为 1,__free_page()会将其归零并归还。3.EXPORT_SYMBOL导出给模块使用,因为 CMA、内存热插拔等子系统可能需要释放连续内存。与alloc_contig_range()的对称性函数操作alloc_contig_range()隔离 + 迁移 + 取走空闲页,返回后页是独立的单页free_contig_range()逐页__free_page(),归还给伙伴系统两者是严格配对的:用alloc_contig_range()分配的连续内存,必须用free_contig_range()释放,不能用free_pages()。为什么不能整体释放?alloc_contig_range()分配的页有几个特殊性:非复合页:没有__GFP_COMP,没有 head/tail 关系,不能作为一个整体处理。独立引用计数:每页引用计数为 1,独立管理。可能不对齐:范围可能不是MAX_ORDER对齐的,无法用单一的order描述。迁移类型可能混合:释放时每页会根据自己的迁移类型归入对应链表。所以只能逐页释放,让伙伴系统在每页释放时自行尝试合并。典型使用场景1. CMA 释放CMA 分配器在释放连续内存时调用free_contig_range()。2. 内存热插拔下线内存的流程中,隔离出的页最终通过它归还。3. 驱动释放 DMA 缓冲某些驱动通过alloc_contig_pages()获取大块连续内存后,用free_contig_range()释放。总结free_contig_range()是alloc_contig_range()的配套逐页释放函数:它遍历[pfn, pfn + nr_pages)中的每一页,调用__free_page()作为 order-0 单页归还给伙伴系统。之所以不能整体释放,是因为alloc_contig_range()分配的页是独立的非复合单页,没有 head/tail 关系,且范围可能不对齐、迁移类型可能混合。它是 CMA、内存热插拔和连续 DMA 缓冲等场景释放连续物理内存的标准接口。
free_contig_range()是alloc_contig_range()的配套释放函数,用于释放通过连续内存分配接口获得的页块。核心作用与背景前面讲过,alloc_contig_range()/alloc_contig_pages()通过隔离和迁移,从伙伴系统中“挖”出一段连续的物理内存。这些页在分配时是独立的单页(每页引用计数为 1,非复合页),因此不能用常规的free_pages()按阶数整体释放。free_contig_range()就是专门用来释放这类连续内存的:逐页释放。核心实现实现非常直接:/** * free_contig_range() - Free pages in a range * @pfn: The start pfn of the pages being freed. * @nr_pages: The number of pages being freed */ void free_contig_range(unsigned long pfn, unsigned long nr_pages) { unsigned long end = pfn + nr_pages; while (pfn < end) __free_page(pfn_to_page(pfn++)); } EXPORT_SYMBOL(free_contig_range);逐步解析1. 计算结束 PFNunsigned long end = pfn + nr_pages;把起始 PFN 和页数转换为[pfn, end)区间。2. 逐页释放while (pfn < end) __free_page(pfn_to_page(pfn++));遍历[pfn, end)中的每一页。对每页调用__free_page()(等价于__free_pages(page, 0)),作为order-0 单页释放回伙伴系统。每页的引用计数在分配时已被设为 1,__free_page()会将其归零并归还。3.EXPORT_SYMBOL导出给模块使用,因为 CMA、内存热插拔等子系统可能需要释放连续内存。与alloc_contig_range()的对称性函数操作alloc_contig_range()隔离 + 迁移 + 取走空闲页,返回后页是独立的单页free_contig_range()逐页__free_page(),归还给伙伴系统两者是严格配对的:用alloc_contig_range()分配的连续内存,必须用free_contig_range()释放,不能用free_pages()。为什么不能整体释放?alloc_contig_range()分配的页有几个特殊性:非复合页:没有__GFP_COMP,没有 head/tail 关系,不能作为一个整体处理。独立引用计数:每页引用计数为 1,独立管理。可能不对齐:范围可能不是MAX_ORDER对齐的,无法用单一的order描述。迁移类型可能混合:释放时每页会根据自己的迁移类型归入对应链表。所以只能逐页释放,让伙伴系统在每页释放时自行尝试合并。典型使用场景1. CMA 释放CMA 分配器在释放连续内存时调用free_contig_range()。2. 内存热插拔下线内存的流程中,隔离出的页最终通过它归还。3. 驱动释放 DMA 缓冲某些驱动通过alloc_contig_pages()获取大块连续内存后,用free_contig_range()释放。总结free_contig_range()是alloc_contig_range()的配套逐页释放函数:它遍历[pfn, pfn + nr_pages)中的每一页,调用__free_page()作为 order-0 单页归还给伙伴系统。之所以不能整体释放,是因为alloc_contig_range()分配的页是独立的非复合单页,没有 head/tail 关系,且范围可能不对齐、迁移类型可能混合。它是 CMA、内存热插拔和连续 DMA 缓冲等场景释放连续物理内存的标准接口。