【问题标题】:Where the structure "struct page" is stored on the linux kernel?结构“struct page”存储在linux内核的哪里?
【发布时间】:2020-10-09 21:33:12
【问题描述】:

我了解到linux内核管理内存,分配/释放内存的单位是4KB,即页面大小。而且我知道这些页面是由 struct page 处理的。 我这里有一个实际的代码。

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;

而且我不知道 linux 内核将这个巨大的(?)结构存储在哪里。 linux 内核中处理了很多页面,这意味着我们有很多这种struct page 结构。它可以存储在内存的什么位置?

我也不知道上面的工会是干什么的。

提前谢谢你。

【问题讨论】:

  • "this huge(?) structure" - 在 32 位架构上,结构的大小小于 50 字节。看:这段文字的大部分是unions。它们的大小甚至写在 cmets 中。
  • 是的,但我想知道这些结构在内存中的位置。如果所有内存都由“页面”管理并且该结构正在管理“页面”,那么 struct page 应该在哪里?
  • 并不是所有的都需要在内存中。 Psge 表也可以交换。

标签: linux memory-management linux-kernel kernel


【解决方案1】:

我最近和你有同样的问题。 Where is the struct page in Linux kernel?

我想我可以给你一些有用的信息。每个节点都将页面存储到pg_data_t的node_mem_map中,并且有一个全局变量mem_map,它指向Node 0的页面数组。

您可以从Professional Linux Kernel Architecture 找到更多详细信息。第 3 章中的部分是“为每个节点创建数据结构”。

【讨论】:

    【解决方案2】:

    首先,有几种内存模型,例如 FMMSMPNUMA。关于虚拟内存、页表和页表、内核结构和用户空间内存的知识可能不会在这里写,因为超出了答案长度的限制,我认为您可以从任何书籍中学习。

    让我们以 NUMA 为例。在 NUMA 中,每个 CPU 都会有一个节点:struct pglist_data *node_data,而这个结构体有很多像ZONE_DMA, ZONE_DMA32, ZONE_NORMAL, ZONE_HIGHMEM, ZONE_MOVALBE 这样的区域,每个区域都有很多struct free_area,而这个结构体包含一个struct page 的列表。

    为什么我们需要使用page?这是因为我们的物理内存是有限的,所以我们创建了虚拟内存。然后我们需要一种机制将虚拟内存加载到物理内存来运行任务(进程或线程)。所以我们使用page作为meta entry,使用一些模型比如NUMA来控制那些页面和页表。

    当我们需要分配一些内存时,我们会使用buddy system和slab/slub分配器来分配内存页面,并将它们添加到可以使用的区域中。当物理内存加载太多页面时,它会使用get_page_from_freelist()kswapd 来换出一些。

    实际上,内存和地址空间是 Linux 内核的重要组成部分。建议你先阅读CSAPP之类的书籍,对操作系统有比较深入的了解,然后再阅读Linux内核源码深入了解。

    【讨论】:

      【解决方案3】:

      如果您想知道它的确切存储位置,this article 可能会给您答案。

      它说它们“通常存储在 ZONE_NORMAL 的开头”。

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      • 我把文章中描述的mem_map存储位置这个看似必不可少的部分加入了。
      猜你喜欢
      • 2021-07-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 2015-05-05
      • 2021-10-18
      • 2019-05-26
      相关资源
      最近更新 更多