简体   繁体   English

linux kernel 结构“struct page”存放在哪里?

[英]Where the structure "struct page" is stored on the linux kernel?

I learned that linux kernel manages the memory and the unit for allocate/deallocate the memory is 4KB, which is the page size.我了解到 linux kernel 管理着 memory 并且分配/释放 memory 的单位是 4KB,这是页面大小。 And I know that this pages are handled by struct page.我知道这个页面是由 struct page 处理的。 I got a actual code here.我在这里得到了一个实际的代码。

struct page {
    unsigned long flags;        /* Atomic flags, some possibly
                     * updated asynchronously */
    /*
     * Five words (20/40 bytes) are available in this union.
     * WARNING: bit 0 of the first word is used for PageTail(). That
     * means the other users of this union MUST NOT use the bit to
     * avoid collision and false-positive PageTail().
     */
    union {
        struct {    /* Page cache and anonymous pages */
            /**
             * @lru: Pageout list, eg. active_list protected by
             * pgdat->lru_lock.  Sometimes used as a generic list
             * by the page owner.
             */
            struct list_head lru;
            /* See page-flags.h for PAGE_MAPPING_FLAGS */
            struct address_space *mapping;
            pgoff_t index;      /* Our offset within mapping. */
            /**
             * @private: Mapping-private opaque data.
             * Usually used for buffer_heads if PagePrivate.
             * Used for swp_entry_t if PageSwapCache.
             * Indicates order in the buddy system if PageBuddy.
             */
            unsigned long private;
        };
        struct {    /* page_pool used by netstack */
            /**
             * @dma_addr: might require a 64-bit value even on
             * 32-bit architectures.
             */
            dma_addr_t dma_addr;
        };
        struct {    /* slab, slob and slub */
            union {
                struct list_head slab_list;
                struct {    /* Partial pages */
                    struct page *next;
#ifdef CONFIG_64BIT
                    int pages;  /* Nr of pages left */
                    int pobjects;   /* Approximate count */
#else
                    short int pages;
                    short int pobjects;
#endif
                };
            };
            struct kmem_cache *slab_cache; /* not slob */
            /* Double-word boundary */
            void *freelist;     /* first free object */
            union {
                void *s_mem;    /* slab: first object */
                unsigned long counters;     /* SLUB */
                struct {            /* SLUB */
                    unsigned inuse:16;
                    unsigned objects:15;
                    unsigned frozen:1;
                };
            };
        };
        struct {    /* Tail pages of compound page */
            unsigned long compound_head;    /* Bit zero is set */

            /* First tail page only */
            unsigned char compound_dtor;
            unsigned char compound_order;
            atomic_t compound_mapcount;
        };
        struct {    /* Second tail page of compound page */
            unsigned long _compound_pad_1;  /* compound_head */
            atomic_t hpage_pinned_refcount;
            /* For both global and memcg */
            struct list_head deferred_list;
        };
        struct {    /* Page table pages */
            unsigned long _pt_pad_1;    /* compound_head */
            pgtable_t pmd_huge_pte; /* protected by page->ptl */
            unsigned long _pt_pad_2;    /* mapping */
            union {
                struct mm_struct *pt_mm; /* x86 pgds only */
                atomic_t pt_frag_refcount; /* powerpc */
            };
#if ALLOC_SPLIT_PTLOCKS
            spinlock_t *ptl;
#else
            spinlock_t ptl;
#endif
        };
        struct {    /* ZONE_DEVICE pages */
            /** @pgmap: Points to the hosting device page map. */
            struct dev_pagemap *pgmap;
            void *zone_device_data;
            /*
             * ZONE_DEVICE private pages are counted as being
             * mapped so the next 3 words hold the mapping, index,
             * and private fields from the source anonymous or
             * page cache page while the page is migrated to device
             * private memory.
             * ZONE_DEVICE MEMORY_DEVICE_FS_DAX pages also
             * use the mapping, index, and private fields when
             * pmem backed DAX files are mapped.
             */
        };

        /** @rcu_head: You can use this to free a page by RCU. */
        struct rcu_head rcu_head;
    };

    union {     /* This union is 4 bytes in size. */
        /*
         * If the page can be mapped to userspace, encodes the number
         * of times this page is referenced by a page table.
         */
        atomic_t _mapcount;

        /*
         * If the page is neither PageSlab nor mappable to userspace,
         * the value stored here may help determine what this page
         * is used for.  See page-flags.h for a list of page types
         * which are currently stored here.
         */
        unsigned int page_type;

        unsigned int active;        /* SLAB */
        int units;          /* SLOB */
    };

    /* Usage count. *DO NOT USE DIRECTLY*. See page_ref.h */
    atomic_t _refcount;

#ifdef CONFIG_MEMCG
    struct mem_cgroup *mem_cgroup;
#endif

    /*
     * On machines where all RAM is mapped into kernel address space,
     * we can simply calculate the virtual address. On machines with
     * highmem some memory is mapped into kernel virtual memory
     * dynamically, so we need a place to store that address.
     * Note that this field could be 16 bits on x86 ... ;)
     *
     * Architectures with slow multiplication can define
     * WANT_PAGE_VIRTUAL in asm/page.h
     */
#if defined(WANT_PAGE_VIRTUAL)
    void *virtual;          /* Kernel virtual address (NULL if
                       not kmapped, ie. highmem) */
#endif /* WANT_PAGE_VIRTUAL */

#ifdef LAST_CPUPID_NOT_IN_PAGE_FLAGS
    int _last_cpupid;
#endif
} _struct_page_alignment;

And I have no idea where the linux kernel stores this huge(?) structure.而且我不知道 linux kernel 在哪里存储这个巨大的(?)结构。 There are a lot of pages handled in the linux kernel and that means that we have a lot of this struct page structures.在 linux kernel 中处理了很多页面,这意味着我们有很多这样的struct page结构。 Where can it be stored on the memory? memory可以存放在哪里?

Also I have no idea what the union up there is up for.我也不知道上面的工会是干什么的。

First, there are several memory models like FMM , SMP , and NUMA .首先,有几个 memory 模型,如FMMSMPNUMA The knowledge about virtual memory, page and page tables, sturct of kernel and user space memory may not write here because there are too much more than the limitation of the answer's length and I think you can learn it from any books.关于virtual memory,page和page tables,kernel的sturct和user space memory的知识这里可能就不写了,因为太多了,超出了答案的长度限制,我想你可以从任何书上学习。

Let's use NUMA as an example.我们以 NUMA 为例。 In NUMA, every CPU will have a node: struct pglist_data *node_data , and this struct has many Zones like ZONE_DMA, ZONE_DMA32, ZONE_NORMAL, ZONE_HIGHMEM, ZONE_MOVALBE , every Zone has many struct free_area , and this struct includes a list of struct page .在 NUMA 中,每个 CPU 都会有一个节点: struct pglist_data *node_data ,这个结构体有很多 Zone,比如ZONE_DMA, ZONE_DMA32, ZONE_NORMAL, ZONE_HIGHMEM, ZONE_MOVALBE ,每个 Zone 都有很多struct free_area ,这个 struct 包含一个struct page列表。

Why we need to use page ?为什么我们需要使用page It is because our physical memory is limit, so we create virtual memory. And then we need a mechanism to load virtual memory to physical memory to run the task(process or thread).这是因为我们的物理memory是有限的,所以我们创建虚拟memory。然后我们需要一种机制将虚拟memory加载到物理memory以运行任务(进程或线程)。 So we use page as the meta entry, and use some models like NUMA to control those pages and page tables.所以我们使用页面作为元条目,并使用一些模型,如 NUMA 来控制这些页面和页表。

When we need to allocate some memory, we will use buddy system and slab/slub allocator to allocate memory pages and add them to a zone that can use.当我们需要分配一些memory时,我们会使用buddy系统和slab/slub分配器分配memory页,并将它们添加到一个可以使用的区域。 When the physical memory loads too much pages, it will use get_page_from_freelist() or kswapd to swap some out.当物理 memory 加载太多页面时,它会使用get_page_from_freelist()kswapd换出一些。

Auctally, memory and addresses space is a essential part of Linux kernel. I suggest you to read some books like CSAPP to get a relatively deep understand of OS, and then reading Linux kernel source codes to dive into them.实际上,memory和地址空间是Linux kernel的重要组成部分。建议大家多看一些CSAPP之类的书,对OS有比较深的了解,再看Linux kernel的源码深入了解。

I have the same question as you recently.我最近和你有同样的问题。 Where is the struct page in Linux kernel? Linux kernel中的结构页在哪里?

And I think I can give you some helpful informations.我想我可以给你一些有用的信息。 Every node stores pages into pg_data_t's node_mem_map , and there is a global variable mem_map , which is pointing to Node 0's page array.每个节点都将页面存储到 pg_data_t 的node_mem_map中,并且有一个全局变量mem_map ,它指向节点 0 的页面数组。

You can find more details from Professional Linux Kernel Architecture .您可以从Professional Linux Kernel Architecture中找到更多详细信息。 In chapter 3, the section is "Creating Data Structures for Each Node".在第 3 章中,该部分是“为每个节点创建数据结构”。

If you want to know exact place where it is stored, this article might give you the answer.如果您想知道它的确切存储位置, 这篇文章可能会给您答案。

It says that they are "usually stored at the beginning of ZONE_NORMAL".它说它们“通常存储在 ZONE_NORMAL 的开头”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM