title: What is the page entry size in Linux?
body: <p>From <a href="https://stackoverflow.com/questions/23017488/what-is-page-table-entry-size">this question</a>, I can conclude that the page entry size is usually 4 bytes for 32-bit systems.</p>
  <p>But looking at the source code of Linux to see how pages are represented, <a href="https://github.com/torvalds/linux/blob/master/include/linux/mm_types.h#L68" rel="nofollow noreferrer">here</a>, I can see that the size of the struct is way bigger than 4 bytes.</p>
  <p>The code for the <code>page</code> struct:</p>
  <pre><code>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-&gt;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;
              unsigned int compound_nr; /* 1 &lt;&lt; compound_order */
          };
          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-&gt;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
      union {
          struct mem_cgroup *mem_cgroup;
          struct obj_cgroup **obj_cgroups;
      };
  #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;
  </code></pre>
  <p>Does the kernel maintain an another representation for the pages other than the page table? What is the relationship between this struct and the page table entries?</p>
  <p>Does the kernel use this struct to represent only used pages? What is this struct used for?</p>
  <p>The picture is not so clear to me.</p>