Linux内核API alloc_pages

alloc_pages函数功能描述:alloc_pages( )函数以gfp_mask分配方式分配2的order次方(1<<order)个连续的物理页。

alloc_pages文件包含

#include<linux/gfp.h>

alloc_pages函数定义

在内核源码中的位置:linux-3.19.3/include/linux/gfp.h

函数定义格式:

static inline struct page * alloc_pages(gfp_t gfp_mask, unsigned int order)

alloc_pages输入参数说明

gfp_mask:是分配标志,内核分配内存有多种方式,该参数告诉内核如何分配以及在哪分配所需的内存,内存分配最终总是调用__get_free_pages( )来实现,这也是GFP_前缀的由来。其中分配标志(gfp_mask)的取值定义见文件linux-3.19.3/include/linux/gfp.h可以取以下各值:

  • GFP_KERNEL:该分配方式最常用,是内核内存的正常分配,它可能睡眠。
  • GFP_ATOMIC:该分配方式常用来从中断处理和进程上下文之外的其他代码中分配内存,从不睡眠。
  • GFP_USER:用来为用户空间分配内存页,可能睡眠。
  • GFP_HIGHUSER:类似GFP_USER,如果有高端内存,就从高端内存分配页。
  • GFP_NOIO、GFP_NOFS:功能类似于GFP_KERNEL,但是为内核分配内存的工作增加了限制。具有GFP_NOFS的分配不允许执行任何文件系统调用,而GFP_NOIO禁止任何I/O初始化。它们主要用在文件系统和虚拟内存代码,那里允许分配休眠,但不应发生递归的文件系统调用。

有的标志用双下划线作为前缀,它们可与上面标志“或”起来使用,以控制分配方式:

  • __GFP_DMA:要求分配可用于DMA的内存。
  • __GFP_HIGHMEM:分配的内存可以位于高端内存。
  • __GFP_NOWARN:当一个分配无法满足,阻止内核发出警告(使用printk )。
  • __GFP_HIGH:高优先级请求,允许为紧急状况消耗被内核保留的最后一些内存页。__GFP_REPEAT、__GFP_NOFAIL、__GFP_NORETRY:告诉分配器当满足一个分配有困难时,如何动作。__GFP_REPEAT表示努力再尝试一次,仍然可能失败;__GFP_NOFAIL告诉分配器尽最大努力来满足要求,始终不返回失败,不推荐使用;__GFP_NORETRY告知分配器如果无法满足请求,立即返回。

order:指要释放的物理页数,其取值为2的order次方个。

alloc_pages返回参数说明

alloc_pages( )函数返回page结构体指针,指向所分配的物理页中的第一个页,如果分配不成功,则返回NULL。

内核用struct page结构表示系统中的每个页框,结构体page在内核文件linux-3.19.3/include/linux/mm_types.h中定义。

alloc_pages实例解析

编写测试文件:alloc_page.c

头文件及全局变量声明如下:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/mm_types.h>
#include <linux/mm.h>
MODULE_LICENSE("GPL");
static int __init alloc_pages_init(void);
static void __exit alloc_pages_exit(void);
struct page * pages = NULL;

模块初始化函数:

int __init alloc_pages_init(void)
{
    pages = alloc_pages(GFP_KERNEL,3);  //分配8个物理页
    if(! pages)
    {
        return -ENOMEM;
    }
    else
    {
        printk("alloc_pages Successfully! \n");
        printk("page_address(pages) = 0x%lx\n", (unsigned long)page_address(pages));
    }
    return 0;
}

模块退出函数:

void __exit alloc_pages_exit(void)
{
    if(pages)
    {
        __free_pages(pages,3);    //释放所分配的8个页
        printk("__free_pages ok! \n");
    }
    printk("exit\n");
}

模块初始化及退出函数调用:

module_init(alloc_pages_init);
module_exit(alloc_pages_exit);

实例运行结果及分析:

首先编译模块,执行命令insmod alloc_pages.ko插入模块,然后执行命令dmesg -c,会出现如图所示的结果。

Linux内核API alloc_pages

执行命令rmmod alloc_pages.ko卸载模块,再执行命令dmesg -c,会出现如图所示的结果。

Linux内核API alloc_pages

结果分析:

测试程序中调用了内核函数alloc_pages( )分配2的3次方即8个连续的物理页面,返回指针赋值给pages,指向所分配的物理页中第一个页的结构体。之后通过输出pages相关的一些信息来获取页的分配情况。

输出pages的虚拟地址为0xffff88013e228000。在模块退出时调用__free_pages( )函数释放以pages指针所指向的页为首的2的3次方个连续的物理页面,参考本教程关于该函数的分析。

赞(1)
未经允许不得转载:极客笔记 » Linux内核API alloc_pages

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
Linux内核API 模块机制
Linux内核API 模块机制Linux内核API __module_addressLinux内核API __module_text_addressLinux内核API __print_symbolLinux内核API __symbol_getLinux内核API __symbol_putLinux内核API find_moduleLinux内核API find_symbolLinux内核API module_is_liveLinux内核API module_putLinux内核API module_refcountLinux内核API sprint_symbolLinux内核API symbol_put_addrLinux内核API try_module_get
Linux内核API 进程管理
Linux内核API 进程管理Linux内核API __task_pid_nr_nsLinux内核API find_get_pidLinux内核API find_pid_nsLinux内核API find_vpidLinux内核API get_pidLinux内核API get_task_mmLinux内核API mmputLinux内核API ns_of_pidLinux内核API pid_nrLinux内核API pid_taskLinux内核API pid_vnrLinux内核API put_pidLinux内核API task_active_pid_nsLinux内核API task_tgid_nr_ns
Linux内核API 进程调度
Linux内核API 进程调度Linux内核API __wake_upLinux内核API __wake_up_syncLinux内核API __wake_up_sync_keyLinux内核API abort_exclusive_waitLinux内核API add_wait_queueLinux内核API add_wait_queue_exclusiveLinux内核API autoremove_wake_functionLinux内核API completeLinux内核API complete_allLinux内核API completion_doneLinux内核API current_thread_infoLinux内核API default_wake_functionLinux内核API do_exitLinux内核API finish_waitLinux内核API init_waitqueue_entryLinux内核API init_waitqueue_headLinux内核API kthread_create_on_nodeLinux内核API kthread_stopLinux内核API prepare_to_waitLinux内核API prepare_to_wait_exclusiveLinux内核API remove_wait_queueLinux内核API sched_setschedulerLinux内核API set_cpus_allowed_ptrLinux内核API set_user_niceLinux内核API task_niceLinux内核API try_wait_for_completionLinux内核API wait_for_completionLinux内核API wait_for_completion_interruptible_timeoutLinux内核API wait_for_completion_killableLinux内核API wait_for_completion_timeoutLinux内核API wake_up_processLinux内核API yield
Linux内核API 中断机制
Linux内核API 中断机制Linux内核API __tasklet_hi_scheduleLinux内核API __tasklet_scheduleLinux内核API disable_irqLinux内核API disable_irq_nosyncLinux内核API disable_irq_wakeLinux内核API enable_irqLinux内核API enable_irq_wakeLinux内核API free_irqLinux内核API irq_set_chipLinux内核API irq_set_chip_dataLinux内核API irq_set_irq_typeLinux内核API irq_set_irq_wakeLinux内核API remove_irqLinux内核API request_irqLinux内核API request_threaded_irqLinux内核API setup_irqLinux内核API tasklet_disableLinux内核API tasklet_disable_nosyncLinux内核API tasklet_enableLinux内核API tasklet_hi_scheduleLinux内核API tasklet_initLinux内核API tasklet_killLinux内核API tasklet_scheduleLinux内核API tasklet_trylockLinux内核API tasklet_unlock
Linux内核API 内存管理
Linux内核API 内存管理Linux内核API __free_pagesLinux内核API __get_free_pagesLinux内核API __get_vm_areaLinux内核API __kreallocLinux内核API alloc_pagesLinux内核API alloc_pages_exactLinux内核API find_vmaLinux内核API find_vma_intersectionLinux内核API free_pagesLinux内核API free_pages_exactLinux内核API get_unmapped_areaLinux内核API get_zeroed_pageLinux内核API kcallocLinux内核API kfreeLinux内核API kmallocLinux内核API kmem_cache_allocLinux内核API kmem_cache_createLinux内核API kmem_cache_destroyLinux内核API kmem_cache_freeLinux内核API kmem_cache_zallocLinux内核API kmemdupLinux内核API ksizeLinux内核API kstrdupLinux内核API kstrndupLinux内核API kzallocLinux内核API memdup_userLinux内核API mempool_allocLinux内核API mempool_alloc_pagesLinux内核API mempool_alloc_slabLinux内核API mempool_createLinux内核API mempool_destroyLinux内核API mempool_freeLinux内核API mempool_free_pagesLinux内核API mempool_free_slabLinux内核API mempool_kfreeLinux内核API mempool_kmallocLinux内核API mempool_resizeLinux内核API nr_free_buffer_pagesLinux内核API page_addressLinux内核API page_cache_getLinux内核API page_cache_releaseLinux内核API page_zoneLinux内核API probe_kernel_addressLinux内核API probe_kernel_readLinux内核API vfreeLinux内核API vma_pagesLinux内核API vmallocLinux内核API vmalloc_to_pageLinux内核API vmalloc_to_pfnLinux内核API vmalloc_user
Linux内核API 定时机制
Linux内核API 定时机制Linux内核API __round_jiffiesLinux内核API __round_jiffies_relativeLinux内核API __round_jiffies_upLinux内核API __round_jiffies_up_relativeLinux内核API add_timerLinux内核API current_kernel_timeLinux内核API del_timerLinux内核API del_timer_syncLinux内核API do_gettimeofdayLinux内核API do_settimeofdayLinux内核API get_secondsLinux内核API getnstimeofdayLinux内核API init_timerLinux内核API init_timer_deferrableLinux内核API init_timer_keyLinux内核API init_timer_on_stackLinux内核API init_timer_on_stack_keyLinux内核API mktimeLinux内核API mod_timerLinux内核API mod_timer_pendingLinux内核API ns_to_timespecLinux内核API ns_to_timevalLinux内核API round_jiffiesLinux内核API round_jiffies_relativeLinux内核API round_jiffies_upLinux内核API round_jiffies_up_relativeLinux内核API set_normalized_timespecLinux内核API setup_timerLinux内核API setup_timer_on_stackLinux内核API timer_pendingLinux内核API timespec_add_nsLinux内核API timespec_compareLinux内核API timespec_equalLinux内核API timespec_subLinux内核API timespec_to_nsLinux内核API timeval_compareLinux内核API timeval_to_nsLinux内核API try_to_del_timer_sync
Linux内核API 同步机制
Linux内核API 同步机制Linux内核API atomic_addLinux内核API atomic_add_negativeLinux内核API atomic_add_returnLinux内核API atomic_add_unlessLinux内核API atomic_cmpxchgLinux内核API atomic_decLinux内核API atomic_dec_and_testLinux内核API atomic_incLinux内核API atomic_inc_and_testLinux内核API atomic_readLinux内核API atomic_setLinux内核API atomic_subLinux内核API atomic_sub_and_testLinux内核API atomic_sub_returnLinux内核API downLinux内核API down_interruptibleLinux内核API down_killableLinux内核API down_readLinux内核API down_read_trylockLinux内核API down_timeoutLinux内核API down_trylockLinux内核API down_writeLinux内核API down_write_trylockLinux内核API downgrade_writeLinux内核API init_rwsemLinux内核API read_seqbeginLinux内核API read_seqretryLinux内核API sema_initLinux内核API seqlock_initLinux内核API upLinux内核API up_readLinux内核API up_writeLinux内核API write_seqlockLinux内核API write_sequnlock
Linux内核API 文件系统
Linux内核API 文件系统Linux内核API __mnt_is_readonlyLinux内核API current_umaskLinux内核API d_allocLinux内核API d_find_aliasLinux内核API dputLinux内核API fgetLinux内核API generic_fillattrLinux内核API get_fs_typeLinux内核API get_max_filesLinux内核API get_superLinux内核API have_submountsLinux内核API I_BDEVLinux内核API inode_add_bytesLinux内核API inode_get_bytesLinux内核API inode_set_bytesLinux内核API inode_sub_bytesLinux内核API is_bad_inodeLinux内核API make_bad_inodeLinux内核API may_umountLinux内核API may_umount_treeLinux内核API mnt_want_writeLinux内核API notify_changeLinux内核API put_unused_fdLinux内核API unshare_fs_structLinux内核API vfs_fstatLinux内核API vfs_getattrLinux内核API vfs_statfs
Linux内核API 设备管理
Linux内核API 设备管理Linux内核API __class_createLinux内核API __class_registerLinux内核API cdev_addLinux内核API cdev_allocLinux内核API cdev_delLinux内核API cdev_initLinux内核API class_createLinux内核API class_destroyLinux内核API class_registerLinux内核API class_unregisterLinux内核API device_addLinux内核API device_createLinux内核API device_delLinux内核API device_destroyLinux内核API device_initializeLinux内核API device_registerLinux内核API device_renameLinux内核API device_unregisterLinux内核API get_deviceLinux内核API put_deviceLinux内核API register_chrdevLinux内核API unregister_chrdev