hugetlb patches resend
Subsystems (15)
cover hugetlb patches resend
I've resynced to the latest mmotm, and expanded / added rationale in the changelogs where I've thought it to be appropriate.
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/21 hugetlb: factor out prep_new_huge_page
Needed to avoid code duplication in follow up patches.
--- mm/hugetlb.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
mm/hugetlb.c +11 -6
@@ -331,6 +331,16 @@ static int adjust_pool_surplus(int deltareturn ret; } +static void prep_new_huge_page (struct page *page,int nid) +{ +set_compound_page_dtor (page, free_huge_page); +spin_lock (&hugetlb_lock); + nr_huge_pages++; + nr_huge_pages_node[nid]++; +spin_unlock (&hugetlb_lock); +put_page (page);/* free it into the hugepage allocator */ +} +static struct page *alloc_fresh_huge_page_node (int nid) {struct page *page;
@@ -344,12 +354,7 @@ static struct page *alloc_fresh_huge_pag__free_pages (page,HUGETLB_PAGE_ORDER );return NULL ; } -set_compound_page_dtor (page, free_huge_page); -spin_lock (&hugetlb_lock); - nr_huge_pages++; - nr_huge_pages_node[nid]++; -spin_unlock (&hugetlb_lock); -put_page (page);/* free it into the hugepage allocator */ +prep_new_huge_page (page, nid); }return page;
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 2/21 hugetlb: modular state for hugetlb page size
In reply to [email protected]The goal of this patchset is to support multiple hugetlb page sizes. This is achieved by introducing a new struct hstate structure, which encapsulates the important hugetlb state and constants (eg. huge page size, number of huge pages currently allocated, etc).
The hstate structure is then passed around the code which requires these fields, they will do the right thing regardless of the exact hstate they are operating on.
This patch adds the hstate structure, with a single global instance of it (default_hstate), and does the basic work of converting hugetlb to use the hstate.
Future patches will add more hstate structures to allow for different hugetlbfs mounts to have different page sizes.
--- arch/ia64/mm/hugetlbpage.c | 6 arch/powerpc/mm/hugetlbpage.c | 2 arch/sh/mm/hugetlbpage.c | 2 arch/sparc64/mm/hugetlbpage.c | 4 arch/x86/mm/hugetlbpage.c | 4 fs/hugetlbfs/inode.c | 49 +++--- include/asm-ia64/hugetlb.h | 2 include/asm-powerpc/hugetlb.h | 2 include/asm-s390/hugetlb.h | 2 include/asm-sh/hugetlb.h | 2 include/asm-sparc64/hugetlb.h | 2 include/asm-x86/hugetlb.h | 7 include/linux/hugetlb.h | 81 +++++++++- ipc/shm.c | 3 mm/hugetlb.c | 321 ++++++++++++++++++++++-------------------- mm/memory.c | 2 mm/mempolicy.c | 9 - mm/mmap.c | 3 18 files changed, 308 insertions(+), 195 deletions(-)
mm/hugetlb.c +198 -163
@@ -22,18 +22,12 @@#include "internal.h" const unsigned long hugetlb_zero =0 , hugetlb_infinity = ~0UL ; -static unsigned long nr_huge_pages, free_huge_pages, resv_huge_pages; -static unsigned long surplus_huge_pages; -static unsigned long nr_overcommit_huge_pages;unsigned long max_huge_pages;unsigned long sysctl_overcommit_huge_pages; -static struct list_head hugepage_freelists[MAX_NUMNODES ]; -static unsigned int nr_huge_pages_node[MAX_NUMNODES ]; -static unsigned int free_huge_pages_node[MAX_NUMNODES ]; -static unsigned int surplus_huge_pages_node[MAX_NUMNODES ];static gfp_t htlb_alloc_mask =GFP_HIGHUSER ;unsigned long hugepages_treat_as_movable; -static int hugetlb_next_nid; + +struct hstate default_hstate;/* * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
@@ -55,11 +49,11 @@ static pgoff_t vma_page_offset(struct vm* Convert the address within this vma to the page offset within * the mapping, in pagecache page units; huge pages here. */ -static pgoff_t vma_pagecache_offset (struct vm_area_struct *vma, -unsigned long address) +static pgoff_t vma_pagecache_offset (struct hstate *h, +struct vm_area_struct *vma,unsigned long address) { -return ((address - vma->vm_start) >>HPAGE_SHIFT ) + - (vma->vm_pgoff >> (HPAGE_SHIFT -PAGE_SHIFT )); +return ((address - vma->vm_start) >>huge_page_shift (h)) + + (vma->vm_pgoff >>huge_page_order (h)); }#define HPAGE_RESV_OWNER (1UL << (BITS_PER_LONG - 1))
@@ -120,14 +114,15 @@ static int is_vma_resv_set(struct vm_are }/* Decrement the reserved pages in the hugepage pool by one */ -static void decrement_hugepage_resv_vma (struct vm_area_struct *vma) +static void decrement_hugepage_resv_vma (struct hstate *h, +struct vm_area_struct *vma) {if (vma->vm_flags &VM_NORESERVE )return ;if (vma->vm_flags &VM_SHARED ) {/* Shared mappings always use reserves */ - resv_huge_pages--; + h->resv_huge_pages--; }else {/* * Only the process that called mmap() has reserves for
@@ -135,7 +130,7 @@ static void decrement_hugepage_resv_vma(*/ if (is_vma_resv_set (vma,HPAGE_RESV_OWNER )) {unsigned long flags, reserve; - resv_huge_pages--; + h->resv_huge_pages--; flags = (unsigned long )vma->vm_private_data &HPAGE_RESV_MASK ; reserve = (unsigned long )vma->vm_private_data -1 ;
@@ -162,12 +157,13 @@ static int vma_has_private_reserves(strureturn 1 ; } -static void clear_huge_page (struct page *page,unsigned long addr) +static void clear_huge_page (struct page *page, +unsigned long addr,unsigned long sz) {int i;might_sleep (); -for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); i++) { +for (i =0 ; i < sz/PAGE_SIZE ; i++) {cond_resched ();clear_user_highpage (page + i, addr + i *PAGE_SIZE ); }
@@ -177,41 +173,43 @@ static void copy_huge_page(struct page * unsigned long addr, struct vm_area_struct *vma) { int i; +struct hstate *h =hstate_vma (vma);might_sleep (); -for (i =0 ; i <HPAGE_SIZE /PAGE_SIZE ; i++) { +for (i =0 ; i <pages_per_huge_page (h); i++) {cond_resched ();copy_user_highpage (dst + i, src + i, addr + i*PAGE_SIZE , vma); } } -static void enqueue_huge_page (struct page *page) +static void enqueue_huge_page (struct hstate *h,struct page *page) {int nid =page_to_nid (page); -list_add (&page->lru, &hugepage_freelists[nid]); - free_huge_pages++; - free_huge_pages_node[nid]++; +list_add (&page->lru, &h->hugepage_freelists[nid]); + h->free_huge_pages++; + h->free_huge_pages_node[nid]++; } -static struct page *dequeue_huge_page (void ) +static struct page *dequeue_huge_page (struct hstate *h) {int nid;struct page *page =NULL ;for (nid =0 ; nid <MAX_NUMNODES ; ++nid) { -if (!list_empty (&hugepage_freelists[nid])) { - page =list_entry (hugepage_freelists[nid].next, +if (!list_empty (&h->hugepage_freelists[nid])) { + page =list_entry (h->hugepage_freelists[nid].next, struct page, lru);list_del (&page->lru); - free_huge_pages--; - free_huge_pages_node[nid]--; + h->free_huge_pages--; + h->free_huge_pages_node[nid]--;break ; } }return page; } -static struct page *dequeue_huge_page_vma (struct vm_area_struct *vma, +static struct page *dequeue_huge_page_vma (struct hstate *h, +struct vm_area_struct *vma,unsigned long address,int avoid_reserve) {int nid;
@@ -229,26 +227,26 @@ static struct page *dequeue_huge_page_vm* not "stolen". The child may still get SIGKILLed */ if (!vma_has_private_reserves (vma) && - free_huge_pages - resv_huge_pages ==0 ) + h->free_huge_pages - h->resv_huge_pages ==0 )return NULL ;/* If reserves cannot be used, ensure enough pages are in the pool */ -if (avoid_reserve && free_huge_pages - resv_huge_pages ==0 ) +if (avoid_reserve && h->free_huge_pages - h->resv_huge_pages ==0 )return NULL ;for_each_zone_zonelist_nodemask (zone, z, zonelist,MAX_NR_ZONES -1 , nodemask) { nid =zone_to_nid (zone);if (cpuset_zone_allowed_softwall (zone, htlb_alloc_mask) && - !list_empty (&hugepage_freelists[nid])) { - page =list_entry (hugepage_freelists[nid].next, + !list_empty (&h->hugepage_freelists[nid])) { + page =list_entry (h->hugepage_freelists[nid].next, struct page, lru);list_del (&page->lru); - free_huge_pages--; - free_huge_pages_node[nid]--; + h->free_huge_pages--; + h->free_huge_pages_node[nid]--;if (!avoid_reserve) -decrement_hugepage_resv_vma (vma); +decrement_hugepage_resv_vma (h, vma);break ; }
@@ -257,12 +255,13 @@ static struct page *dequeue_huge_page_vmreturn page; } -static void update_and_free_page (struct page *page) +static void update_and_free_page (struct hstate *h,struct page *page) {int i; - nr_huge_pages--; - nr_huge_pages_node[page_to_nid (page)]--; -for (i =0 ; i < (HPAGE_SIZE /PAGE_SIZE ); i++) { + + h->nr_huge_pages--; + h->nr_huge_pages_node[page_to_nid (page)]--; +for (i =0 ; i <pages_per_huge_page (h); i++) { page[i].flags &= ~(1 << PG_locked |1 << PG_error |1 << PG_referenced |1 << PG_dirty |1 << PG_active |1 << PG_reserved |1 << PG_private |1 << PG_writeback);
@@ -270,11 +269,16 @@ static void update_and_free_page(structset_compound_page_dtor (page,NULL );set_page_refcounted (page);arch_release_hugepage (page); -__free_pages (page,HUGETLB_PAGE_ORDER ); +__free_pages (page,huge_page_order (h)); }static void free_huge_page (struct page *page) { +/* +* Can't pass hstate in here because it is called from the +* compound page destructor. +*/ +struct hstate *h = &default_hstate;int nid =page_to_nid (page);struct address_space *mapping;
@@ -284,12 +288,12 @@ static void free_huge_page(struct page *INIT_LIST_HEAD (&page->lru);spin_lock (&hugetlb_lock); -if (surplus_huge_pages_node[nid]) { -update_and_free_page (page); - surplus_huge_pages--; - surplus_huge_pages_node[nid]--; +if (h->surplus_huge_pages_node[nid]) { +update_and_free_page (h, page); + h->surplus_huge_pages--; + h->surplus_huge_pages_node[nid]--; }else { -enqueue_huge_page (page); +enqueue_huge_page (h, page); }spin_unlock (&hugetlb_lock);if (mapping)
@@ -301,7 +305,7 @@ static void free_huge_page(struct page ** balanced by operating on them in a round-robin fashion. * Returns 1 if an adjustment was made. */ -static int adjust_pool_surplus (int delta) +static int adjust_pool_surplus (struct hstate *h,int delta) {static int prev_nid;int nid = prev_nid;
@@ -314,15 +318,15 @@ static int adjust_pool_surplus(int delta nid =first_node (node_online_map);/* To shrink on this node, there must be a surplus page */ -if (delta <0 && !surplus_huge_pages_node[nid]) +if (delta <0 && !h->surplus_huge_pages_node[nid])continue ;/* Surplus cannot exceed the total number of pages */ -if (delta >0 && surplus_huge_pages_node[nid] >= - nr_huge_pages_node[nid]) +if (delta >0 && h->surplus_huge_pages_node[nid] >= + h->nr_huge_pages_node[nid])continue ; - surplus_huge_pages += delta; - surplus_huge_pages_node[nid] += delta; + h->surplus_huge_pages += delta; + h->surplus_huge_pages_node[nid] += delta; ret =1 ;break ; }while (nid != prev_nid);
@@ -331,46 +335,46 @@ static int adjust_pool_surplus(int deltareturn ret; } -static void prep_new_huge_page (struct page *page,int nid) +static void prep_new_huge_page (struct hstate *h,struct page *page,int nid) {set_compound_page_dtor (page, free_huge_page);spin_lock (&hugetlb_lock); - nr_huge_pages++; - nr_huge_pages_node[nid]++; + h->nr_huge_pages++; + h->nr_huge_pages_node[nid]++;spin_unlock (&hugetlb_lock);put_page (page);/* free it into the hugepage allocator */ } -static struct page *alloc_fresh_huge_page_node (int nid) +static struct page *alloc_fresh_huge_page_node (struct hstate *h,int nid) {struct page *page; page =alloc_pages_node (nid, htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); +huge_page_order (h));if (page) {if (arch_prepare_hugepage (page)) {__free_pages (page,HUGETLB_PAGE_ORDER );return NULL ; } -prep_new_huge_page (page, nid); +prep_new_huge_page (h, page, nid); }return page; } -static int alloc_fresh_huge_page (void ) +static int alloc_fresh_huge_page (struct hstate *h) {struct page *page;int start_nid;int next_nid;int ret =0 ; - start_nid = hugetlb_next_nid; + start_nid = h->hugetlb_next_nid; do { - page = alloc_fresh_huge_page_node(hugetlb_next_nid); + page = alloc_fresh_huge_page_node(h, h->hugetlb_next_nid); if (page) ret = 1; /*
@@ -384,11 +388,11 @@ static int alloc_fresh_huge_page(void)* if we just successfully allocated a hugepage so that * the next caller gets hugepages on the next node. */ - next_nid =next_node (hugetlb_next_nid, node_online_map); + next_nid =next_node (h->hugetlb_next_nid, node_online_map);if (next_nid ==MAX_NUMNODES ) next_nid =first_node (node_online_map); - hugetlb_next_nid = next_nid; - }while (!page && hugetlb_next_nid != start_nid); + h->hugetlb_next_nid = next_nid; + }while (!page && h->hugetlb_next_nid != start_nid);if (ret)count_vm_event (HTLB_BUDDY_PGALLOC );
@@ -398,8 +402,8 @@ static int alloc_fresh_huge_page(void)return ret; } -static struct page *alloc_buddy_huge_page (struct vm_area_struct *vma, -unsigned long address) +static struct page *alloc_buddy_huge_page (struct hstate *h, +struct vm_area_struct *vma,unsigned long address) {struct page *page;unsigned int nid;
@@ -428,18 +432,18 @@ static struct page *alloc_buddy_huge_pag* per-node value is checked there. */ spin_lock (&hugetlb_lock); -if (surplus_huge_pages >= nr_overcommit_huge_pages) { +if (h->surplus_huge_pages >= h->nr_overcommit_huge_pages) {spin_unlock (&hugetlb_lock);return NULL ; }else { - nr_huge_pages++; - surplus_huge_pages++; + h->nr_huge_pages++; + h->surplus_huge_pages++; }spin_unlock (&hugetlb_lock); page =alloc_pages (htlb_alloc_mask|__GFP_COMP| __GFP_REPEAT|__GFP_NOWARN, -HUGETLB_PAGE_ORDER ); +huge_page_order (h));spin_lock (&hugetlb_lock);if (page) {
@@ -454,12 +458,12 @@ static struct page *alloc_buddy_huge_pag/* * We incremented the global counters already */ - nr_huge_pages_node[nid]++; - surplus_huge_pages_node[nid]++; + h->nr_huge_pages_node[nid]++; + h->surplus_huge_pages_node[nid]++;__count_vm_event (HTLB_BUDDY_PGALLOC ); }else { - nr_huge_pages--; - surplus_huge_pages--; + h->nr_huge_pages--; + h->surplus_huge_pages--;__count_vm_event (HTLB_BUDDY_PGALLOC_FAIL ); }spin_unlock (&hugetlb_lock);
@@ -471,16 +475,16 @@ static struct page *alloc_buddy_huge_pag* Increase the hugetlb pool such that it can accomodate a reservation * of size 'delta'. */ -static int gather_surplus_pages (int delta) +static int gather_surplus_pages (struct hstate *h,int delta) {struct list_head surplus_list;struct page *page, *tmp;int ret, i;int needed, allocated; - needed = (resv_huge_pages + delta) - free_huge_pages; + needed = (h->resv_huge_pages + delta) - h->free_huge_pages;if (needed <=0 ) { - resv_huge_pages += delta; + h->resv_huge_pages += delta;return 0 ; }
@@ -491,7 +495,7 @@ static int gather_surplus_pages(int delt retry:spin_unlock (&hugetlb_lock);for (i =0 ; i < needed; i++) { - page =alloc_buddy_huge_page (NULL ,0 ); + page =alloc_buddy_huge_page (h,NULL ,0 );if (!page) {/* * We were not able to allocate enough pages to
@@ -512,7 +516,8 @@ retry:* because either resv_huge_pages or free_huge_pages may have changed. */ spin_lock (&hugetlb_lock); - needed = (resv_huge_pages + delta) - (free_huge_pages + allocated); + needed = (h->resv_huge_pages + delta) - + (h->free_huge_pages + allocated);if (needed >0 ) goto retry;
@@ -525,7 +530,7 @@ retry:* before they are reserved. */ needed += allocated; - resv_huge_pages += delta; + h->resv_huge_pages += delta; ret =0 ; free:/* Free the needed pages to the hugetlb pool */
@@ -533,7 +538,7 @@ free:if ((--needed) <0 )break ;list_del (&page->lru); -enqueue_huge_page (page); +enqueue_huge_page (h, page); }/* Free unnecessary surplus pages to the buddy allocator */
@@ -561,7 +566,8 @@ free:* allocated to satisfy the reservation must be explicitly freed if they were * never used. */ -static void return_unused_surplus_pages (unsigned long unused_resv_pages) +static void return_unused_surplus_pages (struct hstate *h, +unsigned long unused_resv_pages) {static int nid =-1 ;struct page *page;
@@ -576,27 +582,27 @@ static void return_unused_surplus_pages(unsigned long remaining_iterations =num_online_nodes ();/* Uncommit the reservation */ - resv_huge_pages -= unused_resv_pages; + h->resv_huge_pages -= unused_resv_pages; - nr_pages =min (unused_resv_pages, surplus_huge_pages); + nr_pages =min (unused_resv_pages, h->surplus_huge_pages);while (remaining_iterations-- && nr_pages) { nid =next_node (nid, node_online_map);if (nid ==MAX_NUMNODES ) nid =first_node (node_online_map); -if (!surplus_huge_pages_node[nid]) +if (!h->surplus_huge_pages_node[nid])continue ; -if (!list_empty (&hugepage_freelists[nid])) { - page =list_entry (hugepage_freelists[nid].next, +if (!list_empty (&h->hugepage_freelists[nid])) { + page =list_entry (h->hugepage_freelists[nid].next, struct page, lru);list_del (&page->lru); -update_and_free_page (page); - free_huge_pages--; - free_huge_pages_node[nid]--; - surplus_huge_pages--; - surplus_huge_pages_node[nid]--; +update_and_free_page (h, page); + h->free_huge_pages--; + h->free_huge_pages_node[nid]--; + h->surplus_huge_pages--; + h->surplus_huge_pages_node[nid]--; nr_pages--; remaining_iterations =num_online_nodes (); }
@@ -733,13 +739,14 @@ static long region_truncate(struct list_* an instantiated the change should be committed via vma_commit_reservation. * No action is required on failure. */ -static int vma_needs_reservation (struct vm_area_struct *vma,unsigned long addr) +static int vma_needs_reservation (struct hstate *h, +struct vm_area_struct *vma,unsigned long addr) {struct address_space *mapping = vma->vm_file->f_mapping;struct inode *inode = mapping->host;if (vma->vm_flags &VM_SHARED ) { -pgoff_t idx =vma_pagecache_offset (vma, addr); +pgoff_t idx =vma_pagecache_offset (h, vma, addr);return region_chg (&inode->i_mapping->private_list, idx, idx +1 );
@@ -750,14 +757,14 @@ static int vma_needs_reservation(structreturn 0 ; } -static void vma_commit_reservation (struct vm_area_struct *vma, -unsigned long addr) +static void vma_commit_reservation (struct hstate *h, +struct vm_area_struct *vma,unsigned long addr) {struct address_space *mapping = vma->vm_file->f_mapping;struct inode *inode = mapping->host;if (vma->vm_flags &VM_SHARED ) { -pgoff_t idx =vma_pagecache_offset (vma, addr); +pgoff_t idx =vma_pagecache_offset (h, vma, addr);region_add (&inode->i_mapping->private_list, idx, idx +1 ); } }
@@ -765,6 +772,7 @@ static void vma_commit_reservation(strucstatic struct page *alloc_huge_page (struct vm_area_struct *vma,unsigned long addr,int avoid_reserve) { +struct hstate *h =hstate_vma (vma);struct page *page;struct address_space *mapping = vma->vm_file->f_mapping;struct inode *inode = mapping->host;
@@ -777,7 +785,7 @@ static struct page *alloc_huge_page(stru* MAP_NORESERVE mappings may also need pages and quota allocated * if no reserve mapping overlaps. */ - chg =vma_needs_reservation (vma, addr); + chg =vma_needs_reservation (h, vma, addr);if (chg <0 )return ERR_PTR (chg);if (chg)
@@ -785,11 +793,11 @@ static struct page *alloc_huge_page(strureturn ERR_PTR (-ENOSPC );spin_lock (&hugetlb_lock); - page =dequeue_huge_page_vma (vma, addr, avoid_reserve); + page =dequeue_huge_page_vma (h, vma, addr, avoid_reserve);spin_unlock (&hugetlb_lock);if (!page) { - page =alloc_buddy_huge_page (vma, addr); + page =alloc_buddy_huge_page (h, vma, addr);if (!page) {hugetlb_put_quota (inode->i_mapping, chg);return ERR_PTR (-VM_FAULT_OOM );
@@ -799,7 +807,7 @@ static struct page *alloc_huge_page(struset_page_refcounted (page);set_page_private (page, (unsigned long ) mapping); -vma_commit_reservation (vma, addr); +vma_commit_reservation (h, vma, addr);return page; }
@@ -807,21 +815,28 @@ static struct page *alloc_huge_page(strustatic int __init hugetlb_init (void ) {unsigned long i; +struct hstate *h = &default_hstate;if (HPAGE_SHIFT ==0 )return 0 ; +if (!h->order) { + h->order =HPAGE_SHIFT -PAGE_SHIFT ; + h->mask =HPAGE_MASK ; + } +for (i =0 ; i <MAX_NUMNODES ; ++i) -INIT_LIST_HEAD (&hugepage_freelists[i]); +INIT_LIST_HEAD (&h->hugepage_freelists[i]); - hugetlb_next_nid =first_node (node_online_map); + h->hugetlb_next_nid =first_node (node_online_map);for (i =0 ; i < max_huge_pages; ++i) { -if (!alloc_fresh_huge_page ()) +if (!alloc_fresh_huge_page (h))break ; } - max_huge_pages = free_huge_pages = nr_huge_pages = i; -printk ("Total HugeTLB memory allocated, %ld\n" , free_huge_pages); + max_huge_pages = h->free_huge_pages = h->nr_huge_pages = i; +printk (KERN_INFO "Total HugeTLB memory allocated, %ld\n" , + h->free_huge_pages);return 0 ; }module_init (hugetlb_init);
@@ -847,34 +862,36 @@ static unsigned int cpuset_mems_nr(unsig#ifdef CONFIG_SYSCTL #ifdef CONFIG_HIGHMEM -static void try_to_free_low (unsigned long count) +static void try_to_free_low (struct hstate *h,unsigned long count) {int i;for (i =0 ; i <MAX_NUMNODES ; ++i) {struct page *page, *next; -list_for_each_entry_safe (page, next, &hugepage_freelists[i], lru) { -if (count >= nr_huge_pages) +struct list_head *freel = &h->hugepage_freelists[i]; +list_for_each_entry_safe (page, next, freel, lru) { +if (count >= h->nr_huge_pages)return ;if (PageHighMem (page))continue ;list_del (&page->lru);update_and_free_page (page); - free_huge_pages--; - free_huge_pages_node[page_to_nid (page)]--; + h->free_huge_pages--; + h->free_huge_pages_node[page_to_nid (page)]--; } } }#else -static inline void try_to_free_low (unsigned long count) +static inline void try_to_free_low (struct hstate *h,unsigned long count) { }#endif -#define persistent_huge_pages (nr_huge_pages - surplus_huge_pages) +#define persistent_huge_pages (h) (h->nr_huge_pages - h->surplus_huge_pages)static unsigned long set_max_huge_pages (unsigned long count) {unsigned long min_count, ret; +struct hstate *h = &default_hstate;/* * Increase the pool size
@@ -888,19 +905,19 @@ static unsigned long set_max_huge_pages(* within all the constraints specified by the sysctls. */ spin_lock (&hugetlb_lock); -while (surplus_huge_pages && count > persistent_huge_pages) { -if (!adjust_pool_surplus (-1 )) +while (h->surplus_huge_pages && count >persistent_huge_pages (h)) { +if (!adjust_pool_surplus (h,-1 ))break ; } -while (count > persistent_huge_pages) { +while (count >persistent_huge_pages (h)) {/* * If this allocation races such that we no longer need the * page, free_huge_page will handle it by freeing the page * and reducing the surplus. */ spin_unlock (&hugetlb_lock); - ret =alloc_fresh_huge_page (); + ret =alloc_fresh_huge_page (h);spin_lock (&hugetlb_lock);if (!ret) goto out;
@@ -922,21 +939,21 @@ static unsigned long set_max_huge_pages(* and won't grow the pool anywhere else. Not until one of the * sysctls are changed, or the surplus pages go out of use. */ - min_count = resv_huge_pages + nr_huge_pages - free_huge_pages; + min_count = h->resv_huge_pages + h->nr_huge_pages - h->free_huge_pages; min_count =max (count, min_count); -try_to_free_low (min_count); -while (min_count < persistent_huge_pages) { -struct page *page =dequeue_huge_page (); +try_to_free_low (h, min_count); +while (min_count <persistent_huge_pages (h)) { +struct page *page =dequeue_huge_page (h);if (!page)break ; -update_and_free_page (page); +update_and_free_page (h, page); } -while (count < persistent_huge_pages) { -if (!adjust_pool_surplus (1 )) +while (count <persistent_huge_pages (h)) { +if (!adjust_pool_surplus (h,1 ))break ; } out: - ret = persistent_huge_pages; + ret =persistent_huge_pages (h);spin_unlock (&hugetlb_lock);return ret; }
@@ -966,9 +983,10 @@ int hugetlb_overcommit_handler(struct ct struct file *file, void __user *buffer, size_t *length, loff_t *ppos) { + struct hstate *h = &default_hstate;proc_doulongvec_minmax (table, write, file, buffer, length, ppos);spin_lock (&hugetlb_lock); - nr_overcommit_huge_pages = sysctl_overcommit_huge_pages; + h->nr_overcommit_huge_pages = sysctl_overcommit_huge_pages;spin_unlock (&hugetlb_lock);return 0 ; }
@@ -977,37 +995,40 @@ int hugetlb_overcommit_handler(struct ctint hugetlb_report_meminfo (char *buf) { +struct hstate *h = &default_hstate;return sprintf (buf,"HugePages_Total: %5lu\n" "HugePages_Free: %5lu\n" "HugePages_Rsvd: %5lu\n" "HugePages_Surp: %5lu\n" "Hugepagesize: %5lu kB\n" , - nr_huge_pages, - free_huge_pages, - resv_huge_pages, - surplus_huge_pages, -HPAGE_SIZE /1024 ); + h->nr_huge_pages, + h->free_huge_pages, + h->resv_huge_pages, + h->surplus_huge_pages, +1UL << (huge_page_order (h) +PAGE_SHIFT -10 )); }int hugetlb_report_node_meminfo (int nid,char *buf) { +struct hstate *h = &default_hstate;return sprintf (buf,"Node %d HugePages_Total: %5u\n" "Node %d HugePages_Free: %5u\n" "Node %d HugePages_Surp: %5u\n" , - nid, nr_huge_pages_node[nid], - nid, free_huge_pages_node[nid], - nid, surplus_huge_pages_node[nid]); + nid, h->nr_huge_pages_node[nid], + nid, h->free_huge_pages_node[nid], + nid, h->surplus_huge_pages_node[nid]); }/* Return the number pages of memory we physically have, in PAGE_SIZE units. */ unsigned long hugetlb_total_pages (void ) { -return nr_huge_pages * (HPAGE_SIZE /PAGE_SIZE ); +struct hstate *h = &default_hstate; +return h->nr_huge_pages *pages_per_huge_page (h); } -static int hugetlb_acct_memory (long delta) +static int hugetlb_acct_memory (struct hstate *h,long delta) {int ret = -ENOMEM ;
@@ -1030,18 +1051,18 @@ static int hugetlb_acct_memory(long delt* semantics that cpuset has. */ if (delta >0 ) { -if (gather_surplus_pages (delta) <0 ) +if (gather_surplus_pages (h, delta) <0 ) goto out; -if (delta >cpuset_mems_nr (free_huge_pages_node)) { -return_unused_surplus_pages (delta); +if (delta >cpuset_mems_nr (h->free_huge_pages_node)) { +return_unused_surplus_pages (h, delta); goto out; } } ret =0 ;if (delta <0 ) -return_unused_surplus_pages ((unsigned long ) -delta); +return_unused_surplus_pages (h, (unsigned long ) -delta); out:spin_unlock (&hugetlb_lock);
@@ -1050,9 +1071,11 @@ out:static void hugetlb_vm_op_close (struct vm_area_struct *vma) { +struct hstate *h =hstate_vma (vma);unsigned long reserve =vma_resv_huge_pages (vma); +if (reserve) -hugetlb_acct_memory (-reserve); +hugetlb_acct_memory (h, -reserve); }/*
@@ -1108,14 +1131,16 @@ int copy_hugetlb_page_range(struct mm_ststruct page *ptepage;unsigned long addr;int cow; +struct hstate *h =hstate_vma (vma); +unsigned long sz =huge_page_size (h); cow = (vma->vm_flags & (VM_SHARED |VM_MAYWRITE )) ==VM_MAYWRITE ; -for (addr = vma->vm_start; addr < vma->vm_end; addr +=HPAGE_SIZE ) { +for (addr = vma->vm_start; addr < vma->vm_end; addr += sz) { src_pte =huge_pte_offset (src, addr);if (!src_pte)continue ; - dst_pte =huge_pte_alloc (dst, addr); + dst_pte =huge_pte_alloc (dst, addr, sz);if (!dst_pte) goto nomem;
@@ -1151,6 +1176,9 @@ void __unmap_hugepage_range(struct vm_arpte_t pte;struct page *page;struct page *tmp; +struct hstate *h =hstate_vma (vma); +unsigned long sz =huge_page_size (h); +/* * A page gathering list, protected by per file i_mmap_lock. The * lock is used to avoid list corruption from multiple unmapping
@@ -1159,11 +1187,11 @@ void __unmap_hugepage_range(struct vm_arLIST_HEAD (page_list);WARN_ON (!is_vm_hugetlb_page (vma)); -BUG_ON (start & ~HPAGE_MASK ); -BUG_ON (end & ~HPAGE_MASK ); +BUG_ON (start & ~huge_page_mask (h)); +BUG_ON (end & ~huge_page_mask (h));spin_lock (&mm->page_table_lock); -for (address = start; address < end; address +=HPAGE_SIZE ) { +for (address = start; address < end; address += sz) { ptep =huge_pte_offset (mm, address);if (!ptep)continue ;
@@ -1276,6 +1304,7 @@ static int hugetlb_cow(struct mm_struct unsigned long address, pte_t *ptep, pte_t pte, struct page *pagecache_page) { + struct hstate *h = hstate_vma(vma);struct page *old_page, *new_page;int avoidcopy;int outside_reserve =0 ;
@@ -1336,7 +1365,7 @@ retry_avoidcopy:__SetPageUptodate (new_page);spin_lock (&mm->page_table_lock); - ptep =huge_pte_offset (mm, address &HPAGE_MASK ); + ptep =huge_pte_offset (mm, address &huge_page_mask (h));if (likely (pte_same (huge_ptep_get (ptep), pte))) {/* Break COW */ huge_ptep_clear_flush (vma, address, ptep);
@@ -1351,14 +1380,14 @@ retry_avoidcopy: }/* Return the pagecache page at a given address within a VMA */ -static struct page *hugetlbfs_pagecache_page (struct vm_area_struct *vma, -unsigned long address) +static struct page *hugetlbfs_pagecache_page (struct hstate *h, +struct vm_area_struct *vma,unsigned long address) {struct address_space *mapping;pgoff_t idx; mapping = vma->vm_file->f_mapping; - idx =vma_pagecache_offset (vma, address); + idx =vma_pagecache_offset (h, vma, address);return find_lock_page (mapping, idx); }
@@ -1366,6 +1395,7 @@ static struct page *hugetlbfs_pagecache_static int hugetlb_no_page (struct mm_struct *mm,struct vm_area_struct *vma,unsigned long address,pte_t *ptep,int write_access) { +struct hstate *h =hstate_vma (vma);int ret =VM_FAULT_SIGBUS ;pgoff_t idx;unsigned long size;
@@ -1386,7 +1416,7 @@ static int hugetlb_no_page(struct mm_str } mapping = vma->vm_file->f_mapping; - idx =vma_pagecache_offset (vma, address); + idx =vma_pagecache_offset (h, vma, address);/* * Use page lock to guard against racing truncation
@@ -1395,7 +1425,7 @@ static int hugetlb_no_page(struct mm_str retry: page =find_lock_page (mapping, idx);if (!page) { - size =i_size_read (mapping->host) >>HPAGE_SHIFT ; + size =i_size_read (mapping->host) >>huge_page_shift (h);if (idx >= size) goto out; page =alloc_huge_page (vma, address,0 );
@@ -1403,7 +1433,7 @@ retry: ret = -PTR_ERR (page); goto out; } -clear_huge_page (page, address); +clear_huge_page (page, address,huge_page_size (h));__SetPageUptodate (page);if (vma->vm_flags &VM_SHARED ) {
@@ -1419,14 +1449,14 @@ retry: }spin_lock (&inode->i_lock); - inode->i_blocks +=BLOCKS_PER_HUGEPAGE ; + inode->i_blocks +=blocks_per_huge_page (h);spin_unlock (&inode->i_lock); }else lock_page (page); }spin_lock (&mm->page_table_lock); - size =i_size_read (mapping->host) >>HPAGE_SHIFT ; + size =i_size_read (mapping->host) >>huge_page_shift (h);if (idx >= size) goto backout;
@@ -1462,8 +1492,9 @@ int hugetlb_fault(struct mm_struct *mm,pte_t entry;int ret;static DEFINE_MUTEX (hugetlb_instantiation_mutex); +struct hstate *h =hstate_vma (vma); - ptep =huge_pte_alloc (mm, address); + ptep =huge_pte_alloc (mm, address,huge_page_size (h));if (!ptep)return VM_FAULT_OOM ;
@@ -1487,7 +1518,7 @@ int hugetlb_fault(struct mm_struct *mm,if (likely (pte_same (entry,huge_ptep_get (ptep))))if (write_access && !pte_write (entry)) {struct page *page; - page =hugetlbfs_pagecache_page (vma, address); + page =hugetlbfs_pagecache_page (h, vma, address); ret =hugetlb_cow (mm, vma, address, ptep, entry, page);if (page) {unlock_page (page);
@@ -1508,6 +1539,7 @@ int follow_hugetlb_page(struct mm_structunsigned long pfn_offset;unsigned long vaddr = *position;int remainder = *length; +struct hstate *h =hstate_vma (vma);spin_lock (&mm->page_table_lock);while (vaddr < vma->vm_end && remainder) {
@@ -1519,7 +1551,7 @@ int follow_hugetlb_page(struct mm_struct* each hugepage. We have to make * sure we get the * first, for the page indexing below to work. */ - pte =huge_pte_offset (mm, vaddr &HPAGE_MASK ); + pte =huge_pte_offset (mm, vaddr &huge_page_mask (h));if (!pte ||huge_pte_none (huge_ptep_get (pte)) || (write && !pte_write (huge_ptep_get (pte)))) {
@@ -1537,7 +1569,7 @@ int follow_hugetlb_page(struct mm_structbreak ; } - pfn_offset = (vaddr & ~HPAGE_MASK ) >>PAGE_SHIFT ; + pfn_offset = (vaddr & ~huge_page_mask (h)) >>PAGE_SHIFT ; page =pte_page (huge_ptep_get (pte)); same_page:if (pages) {
@@ -1553,7 +1585,7 @@ same_page: --remainder; ++i;if (vaddr < vma->vm_end && remainder && - pfn_offset <HPAGE_SIZE /PAGE_SIZE ) { + pfn_offset <pages_per_huge_page (h)) {/* * We use pfn_offset to avoid touching the pageframes * of this compound page.
@@ -1575,13 +1607,14 @@ void hugetlb_change_protection(struct vmunsigned long start = address;pte_t *ptep;pte_t pte; +struct hstate *h =hstate_vma (vma);BUG_ON (address >= end);flush_cache_range (vma, address, end);spin_lock (&vma->vm_file->f_mapping->i_mmap_lock);spin_lock (&mm->page_table_lock); -for (; address < end; address +=HPAGE_SIZE ) { +for (; address < end; address +=huge_page_size (h)) { ptep =huge_pte_offset (mm, address);if (!ptep)continue ;
@@ -1604,6 +1637,7 @@ int hugetlb_reserve_pages(struct inode * struct vm_area_struct *vma) {long ret, chg; +struct hstate *h =hstate_inode (inode);if (vma && vma->vm_flags &VM_NORESERVE )return 0 ;
@@ -1627,7 +1661,7 @@ int hugetlb_reserve_pages(struct inode *if (hugetlb_get_quota (inode->i_mapping, chg))return -ENOSPC ; - ret =hugetlb_acct_memory (chg); + ret =hugetlb_acct_memory (h, chg);if (ret <0 ) {hugetlb_put_quota (inode->i_mapping, chg);return ret;
@@ -1639,12 +1673,13 @@ int hugetlb_reserve_pages(struct inode *void hugetlb_unreserve_pages (struct inode *inode,long offset,long freed) { +struct hstate *h =hstate_inode (inode);long chg =region_truncate (&inode->i_mapping->private_list, offset);spin_lock (&inode->i_lock); - inode->i_blocks -=BLOCKS_PER_HUGEPAGE * freed; + inode->i_blocks -=blocks_per_huge_page (h);spin_unlock (&inode->i_lock);hugetlb_put_quota (inode->i_mapping, (chg - freed)); -hugetlb_acct_memory (-(chg - freed)); +hugetlb_acct_memory (h, -(chg - freed)); }
arch/powerpc/mm/hugetlbpage.c +2 -1
@@ -128,7 +128,8 @@ pte_t *huge_pte_offset(struct mm_structreturn NULL ; } -pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +pte_t *huge_pte_alloc (struct mm_struct *mm, +unsigned long addr,unsigned long sz) {pgd_t *pg;pud_t *pu;
arch/sparc64/mm/hugetlbpage.c +3 -2
@@ -175,7 +175,7 @@ hugetlb_get_unmapped_area(struct file *freturn -ENOMEM ;if (flags &MAP_FIXED ) { -if (prepare_hugepage_range (addr, len)) +if (prepare_hugepage_range (file, addr, len))return -EINVAL ;return addr; }
@@ -195,7 +195,8 @@ hugetlb_get_unmapped_area(struct file *f pgoff, flags); } -pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +pte_t *huge_pte_alloc (struct mm_struct *mm, +unsigned long addr,unsigned long sz) {pgd_t *pgd;pud_t *pud;
arch/sh/mm/hugetlbpage.c +2 -1
@@ -22,7 +22,8 @@#include <asm/tlbflush.h> #include <asm/cacheflush.h> -pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +pte_t *huge_pte_alloc (struct mm_struct *mm, +unsigned long addr,unsigned long sz) {pgd_t *pgd;pud_t *pud;
arch/ia64/mm/hugetlbpage.c +4 -3
@@ -24,7 +24,7 @@unsigned int hpage_shift=HPAGE_SHIFT_DEFAULT ;pte_t * -huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +huge_pte_alloc (struct mm_struct *mm,unsigned long addr,unsigned long sz) {unsigned long taddr =htlbpage_to_page (addr);pgd_t *pgd;
@@ -75,7 +75,8 @@ int huge_pmd_unshare(struct mm_struct *m* Don't actually need to do any preparation, but need to make sure * the address is in the right region. */ -int prepare_hugepage_range (unsigned long addr,unsigned long len) +int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) {if (len & ~HPAGE_MASK )return -EINVAL ;
@@ -149,7 +150,7 @@ unsigned long hugetlb_get_unmapped_area(/* Handle MAP_FIXED */ if (flags &MAP_FIXED ) { -if (prepare_hugepage_range (addr, len)) +if (prepare_hugepage_range (file, addr, len))return -EINVAL ;return addr; }
arch/x86/mm/hugetlbpage.c +3 -2
@@ -124,7 +124,8 @@ int huge_pmd_unshare(struct mm_struct *mreturn 1 ; } -pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +pte_t *huge_pte_alloc (struct mm_struct *mm, +unsigned long addr,unsigned long sz) {pgd_t *pgd;pud_t *pud;
@@ -368,7 +369,7 @@ hugetlb_get_unmapped_area(struct file *freturn -ENOMEM ;if (flags &MAP_FIXED ) { -if (prepare_hugepage_range (addr, len)) +if (prepare_hugepage_range (file, addr, len))return -EINVAL ;return addr; }
include/linux/hugetlb.h +83 -5
116 lines not on this page · raw message
fs/hugetlbfs/inode.c +30 -22
172 lines not on this page · raw message
ipc/shm.c +2 -1
@@ -562,7 +562,8 @@ static void shm_get_stat(struct ipc_nameif (is_file_hugepages (shp->shm_file)) {struct address_space *mapping = inode->i_mapping; - *rss += (HPAGE_SIZE /PAGE_SIZE )*mapping->nrpages; +struct hstate *h =hstate_file (shp->shm_file); + *rss +=pages_per_huge_page (h) * mapping->nrpages; }else {struct shmem_inode_info *info =SHMEM_I (inode);spin_lock (&info->lock);
mm/memory.c +1 -1
@@ -904,7 +904,7 @@ unsigned long unmap_vmas(struct mmu_gathif (unlikely (is_vm_hugetlb_page (vma))) {unmap_hugepage_range (vma, start, end,NULL ); zap_work -= (end - start) / - (HPAGE_SIZE /PAGE_SIZE ); +pages_per_huge_page (hstate_vma (vma)); start = end; }else start = unmap_page_range(*tlbp, vma,
mm/mempolicy.c +6 -3
@@ -1477,7 +1477,7 @@ struct zonelist *huge_zonelist(struct vmif (unlikely ((*mpol)->mode ==MPOL_INTERLEAVE )) { zl =node_zonelist (interleave_nid (*mpol, vma, addr, -HPAGE_SHIFT ), gfp_flags); +huge_page_shift (hstate_vma (vma))), gfp_flags); }else { zl =policy_zonelist (gfp_flags, *mpol);if ((*mpol)->mode ==MPOL_BIND )
@@ -2216,9 +2216,12 @@ static void check_huge_range(struct vm_a {unsigned long addr;struct page *page; +struct hstate *h =hstate_vma (vma); +unsigned long sz =huge_page_size (h); -for (addr = start; addr < end; addr +=HPAGE_SIZE ) { -pte_t *ptep =huge_pte_offset (vma->vm_mm, addr &HPAGE_MASK ); +for (addr = start; addr < end; addr += sz) { +pte_t *ptep =huge_pte_offset (vma->vm_mm, + addr &huge_page_mask (h));pte_t pte;if (!ptep)
mm/mmap.c +2 -1
@@ -1814,7 +1814,8 @@ int split_vma(struct mm_struct * mm, strstruct mempolicy *pol;struct vm_area_struct *new; -if (is_vm_hugetlb_page (vma) && (addr & ~HPAGE_MASK )) +if (is_vm_hugetlb_page (vma) && (addr & + ~(huge_page_mask (hstate_vma (vma)))))return -EINVAL ;if (mm->map_count >= sysctl_max_map_count)
include/asm-ia64/hugetlb.h +2 -1
@@ -8,7 +8,8 @@ void hugetlb_free_pgd_range(struct mmu_g unsigned long end, unsigned long floor, unsigned long ceiling); -int prepare_hugepage_range (unsigned long addr,unsigned long len); +int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len); static inline int is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
include/asm-powerpc/hugetlb.h +2 -1
@@ -21,7 +21,8 @@ pte_t huge_ptep_get_and_clear(struct mm_* If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range (unsigned long addr,unsigned long len) +static inline int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) {if (len & ~HPAGE_MASK )return -EINVAL ;
include/asm-s390/hugetlb.h +2 -1
@@ -22,7 +22,8 @@ void set_huge_pte_at(struct mm_struct *m* If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range (unsigned long addr,unsigned long len) +static inline int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) {if (len & ~HPAGE_MASK )return -EINVAL ;
include/asm-sh/hugetlb.h +2 -1
@@ -14,7 +14,8 @@ static inline int is_hugepage_only_range* If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range (unsigned long addr,unsigned long len) +static inline int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) {if (len & ~HPAGE_MASK )return -EINVAL ;
include/asm-sparc64/hugetlb.h +2 -1
@@ -22,7 +22,8 @@ static inline int is_hugepage_only_range* If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range (unsigned long addr,unsigned long len) +static inline int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) {if (len & ~HPAGE_MASK )return -EINVAL ;
include/asm-x86/hugetlb.h +5 -3
@@ -14,11 +14,13 @@ static inline int is_hugepage_only_range* If the arch doesn't supply something else, assume that hugepage * size aligned regions are ok without further preparation. */ -static inline int prepare_hugepage_range (unsigned long addr,unsigned long len) +static inline int prepare_hugepage_range (struct file *file, +unsigned long addr,unsigned long len) { -if (len & ~HPAGE_MASK ) +struct hstate *h =hstate_file (file); +if (len & ~huge_page_mask (h))return -EINVAL ; -if (addr & ~HPAGE_MASK ) +if (addr & ~huge_page_mask (h))return -EINVAL ;return 0 ; }
arch/s390/mm/hugetlbpage.c +2 -1
@@ -72,7 +72,8 @@ void arch_release_hugepage(struct page * page[1 ].index =0 ; } -pte_t *huge_pte_alloc (struct mm_struct *mm,unsigned long addr) +pte_t *huge_pte_alloc (struct mm_struct *mm, +unsigned long addr,unsigned long sz) {pgd_t *pgdp;pud_t *pudp;
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 3/21 hugetlb: multiple hstates for multiple page sizes
In reply to [email protected]Add basic support for more than one hstate in hugetlbfs. This is the key to supporting multiple hugetlbfs page sizes at once.
- Rather than a single hstate, we now have an array, with an iterator
- default_hstate continues to be the struct hstate which we use by default
- Add functions for architectures to register new hstates
--- include/linux/hugetlb.h | 16 +++++++ mm/hugetlb.c | 98 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 95 insertions(+), 19 deletions(-)
mm/hugetlb.c +121 -27
@@ -22,12 +22,19 @@#include "internal.h" const unsigned long hugetlb_zero =0 , hugetlb_infinity = ~0UL ; -unsigned long max_huge_pages; -unsigned long sysctl_overcommit_huge_pages;static gfp_t htlb_alloc_mask =GFP_HIGHUSER ;unsigned long hugepages_treat_as_movable; -struct hstate default_hstate; +static int max_hstate =0 ; +unsigned int default_hstate_idx; +struct hstate hstates[HUGE_MAX_HSTATE ]; + +/* for command line parsing */ +static struct hstate *__initdata parsed_hstate =NULL ; +static unsigned long __initdata default_hstate_max_huge_pages =0 ; + +#define for_each_hstate (h) \ + for ((h) = hstates; (h) < &hstates[max_hstate]; (h)++)/* * Protects updates to hugepage_freelists, nr_huge_pages, and free_huge_pages
@@ -272,13 +279,24 @@ static void update_and_free_page(struct__free_pages (page,huge_page_order (h)); } +struct hstate *size_to_hstate (unsigned long size) +{ +struct hstate *h; + +for_each_hstate (h) { +if (huge_page_size (h) == size) +return h; + } +return NULL ; +} +static void free_huge_page (struct page *page) {/* * Can't pass hstate in here because it is called from the * compound page destructor. */ -struct hstate *h = &default_hstate; +struct hstate *h =page_hstate (page);int nid =page_to_nid (page);struct address_space *mapping;
@@ -812,39 +830,94 @@ static struct page *alloc_huge_page(strureturn page; } -static int __init hugetlb_init (void ) +static void __init hugetlb_init_one_hstate (struct hstate *h) {unsigned long i; -struct hstate *h = &default_hstate; - -if (HPAGE_SHIFT ==0 ) -return 0 ; - -if (!h->order) { - h->order =HPAGE_SHIFT -PAGE_SHIFT ; - h->mask =HPAGE_MASK ; - }for (i =0 ; i <MAX_NUMNODES ; ++i)INIT_LIST_HEAD (&h->hugepage_freelists[i]); h->hugetlb_next_nid =first_node (node_online_map); -for (i =0 ; i < max_huge_pages; ++i) { +for (i =0 ; i < h->max_huge_pages; ++i) {if (!alloc_fresh_huge_page (h))break ; } - max_huge_pages = h->free_huge_pages = h->nr_huge_pages = i; -printk (KERN_INFO "Total HugeTLB memory allocated, %ld\n" , - h->free_huge_pages); + h->max_huge_pages = h->free_huge_pages = h->nr_huge_pages = i; +} + +static void __init hugetlb_init_hstates (void ) +{ +struct hstate *h; + +for_each_hstate (h) { +hugetlb_init_one_hstate (h); + } +} + +static void __init report_hugepages (void ) +{ +struct hstate *h; + +for_each_hstate (h) { +printk (KERN_INFO "Total HugeTLB memory allocated, " +"%ld %dMB pages\n" , + h->free_huge_pages, +1 << (h->order +PAGE_SHIFT -20 )); + } +} + +static int __init hugetlb_init (void ) +{ +BUILD_BUG_ON (HPAGE_SHIFT ==0 ); + +if (!size_to_hstate (HPAGE_SIZE )) { +hugetlb_add_hstate (HUGETLB_PAGE_ORDER ); + parsed_hstate->max_huge_pages = default_hstate_max_huge_pages; + } + default_hstate_idx =size_to_hstate (HPAGE_SIZE ) - hstates; + +hugetlb_init_hstates (); + +report_hugepages (); +return 0 ; }module_init (hugetlb_init); +/* Should be called on processing a hugepagesz=... option */ +void __init hugetlb_add_hstate (unsigned order) +{ +struct hstate *h; +if (size_to_hstate (PAGE_SIZE << order)) { +printk (KERN_WARNING "hugepagesz= specified twice, ignoring\n" ); +return ; + } +BUG_ON (max_hstate >=HUGE_MAX_HSTATE ); +BUG_ON (order ==0 ); + h = &hstates[max_hstate++]; + h->order = order; + h->mask = ~((1ULL << (order +PAGE_SHIFT )) -1 ); +hugetlb_init_one_hstate (h); + parsed_hstate = h; +} +static int __init hugetlb_setup (char *s) { -if (sscanf (s,"%lu" , &max_huge_pages) <=0 ) - max_huge_pages =0 ; +unsigned long *mhp; + +/* +* !max_hstate means we haven't parsed a hugepagesz= parameter yet, +* so this hugepages= parameter goes to the "default hstate". +*/ +if (!max_hstate) + mhp = &default_hstate_max_huge_pages; +else + mhp = &parsed_hstate->max_huge_pages; + +if (sscanf (s,"%lu" , mhp) <=0 ) + *mhp =0 ; +return 1 ; }__setup ("hugepages=" , hugetlb_setup);
@@ -875,7 +948,7 @@ static void try_to_free_low(struct hstatif (PageHighMem (page))continue ;list_del (&page->lru); -update_and_free_page (page); +update_and_free_page (h, page); h->free_huge_pages--; h->free_huge_pages_node[page_to_nid (page)]--; }
@@ -888,10 +961,9 @@ static inline void try_to_free_low(struc#endif #define persistent_huge_pages (h) (h->nr_huge_pages - h->surplus_huge_pages) -static unsigned long set_max_huge_pages (unsigned long count) +static unsigned long set_max_huge_pages (struct hstate *h,unsigned long count) {unsigned long min_count, ret; -struct hstate *h = &default_hstate;/* * Increase the pool size
@@ -962,8 +1034,19 @@ int hugetlb_sysctl_handler(struct ctl_ta struct file *file, void __user *buffer, size_t *length, loff_t *ppos) { + struct hstate *h = &default_hstate; +unsigned long tmp; + +if (!write) + tmp = h->max_huge_pages; + + table->data = &tmp; + table->maxlen =sizeof (unsigned long );proc_doulongvec_minmax (table, write, file, buffer, length, ppos); - max_huge_pages =set_max_huge_pages (max_huge_pages); + +if (write) + h->max_huge_pages =set_max_huge_pages (h, tmp); +return 0 ; }
@@ -984,10 +1067,21 @@ int hugetlb_overcommit_handler(struct ct size_t *length, loff_t *ppos) { struct hstate *h = &default_hstate; +unsigned long tmp; + +if (!write) + tmp = h->nr_overcommit_huge_pages; + + table->data = &tmp; + table->maxlen =sizeof (unsigned long );proc_doulongvec_minmax (table, write, file, buffer, length, ppos); -spin_lock (&hugetlb_lock); - h->nr_overcommit_huge_pages = sysctl_overcommit_huge_pages; -spin_unlock (&hugetlb_lock); + +if (write) { +spin_lock (&hugetlb_lock); + h->nr_overcommit_huge_pages = tmp; +spin_unlock (&hugetlb_lock); + } +return 0 ; }
include/linux/hugetlb.h +16 -3
@@ -36,8 +36,6 @@ int hugetlb_reserve_pages(struct inode * struct vm_area_struct *vma);void hugetlb_unreserve_pages (struct inode *inode,long offset,long freed); -extern unsigned long max_huge_pages; -extern unsigned long sysctl_overcommit_huge_pages;extern unsigned long hugepages_treat_as_movable;extern const unsigned long hugetlb_zero, hugetlb_infinity;extern int sysctl_hugetlb_shm_group;
@@ -181,7 +179,17 @@ struct hstate {unsigned int surplus_huge_pages_node[MAX_NUMNODES ]; }; -extern struct hstate default_hstate; +void __init hugetlb_add_hstate (unsigned order); +struct hstate *size_to_hstate (unsigned long size); + +#ifndef HUGE_MAX_HSTATE +#define HUGE_MAX_HSTATE 1 +#endif + +extern struct hstate hstates[HUGE_MAX_HSTATE ]; +extern unsigned int default_hstate_idx; + +#define default_hstate (hstates[default_hstate_idx])static inline struct hstate *hstate_vma (struct vm_area_struct *vma) {
@@ -230,6 +238,11 @@ static inline unsigned int blocks_per_hu#include <asm/hugetlb.h> +static inline struct hstate *page_hstate (struct page *page) +{ +return size_to_hstate (PAGE_SIZE <<compound_order (page)); +} +#else struct hstate {};#define hstate_file (f) NULL
kernel/sysctl.c +5 -3
@@ -926,7 +926,7 @@ static struct ctl_table vm_table[] = {#ifdef CONFIG_HUGETLB_PAGE { .procname = "nr_hugepages", - .data = &max_huge_pages, + .data = NULL, .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = &hugetlb_sysctl_handler,
@@ -952,10 +952,12 @@ static struct ctl_table vm_table[] = { { .ctl_name = CTL_UNNUMBERED, .procname = "nr_overcommit_hugepages", - .data = &sysctl_overcommit_huge_pages, - .maxlen = sizeof(sysctl_overcommit_huge_pages), + .data = NULL, + .maxlen = sizeof(unsigned long), .mode = 0644, .proc_handler = &hugetlb_overcommit_handler, + .extra1 = (void *)&hugetlb_zero, + .extra2 = (void *)&hugetlb_infinity, }, #endif {
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 4/21 hugetlbfs: per mount huge page sizes
In reply to [email protected]Add the ability to configure the hugetlb hstate used on a per mount basis.
- Add a new pagesize= option to the hugetlbfs mount that allows setting the page size
- This option causes the mount code to find the hstate corresponding to the specified size, and sets up a pointer to the hstate in the mount's superblock.
- Change the hstate accessors to use this information rather than the global_hstate they were using (requires a slight change in mm/memory.c so we don't NULL deref in the error-unmap path -- see comments).
[np: take hstate out of hugetlbfs inode and vma->vm_private_data]
--- fs/hugetlbfs/inode.c | 48 ++++++++++++++++++++++++++++++++++++++---------- include/linux/hugetlb.h | 14 +++++++++----- mm/hugetlb.c | 16 +++------------- mm/memory.c | 18 ++++++++++++++++-- 4 files changed, 66 insertions(+), 30 deletions(-)
include/linux/hugetlb.h +9 -5
@@ -100,6 +100,7 @@ struct hugetlbfs_config {umode_t mode;long nr_blocks;long nr_inodes; +struct hstate *hstate; };struct hugetlbfs_sb_info {
@@ -108,6 +109,7 @@ struct hugetlbfs_sb_info {long max_inodes;/* inodes allowed */ long free_inodes;/* inodes free */ spinlock_t stat_lock; +struct hstate *hstate; };
@@ -191,19 +193,21 @@ extern unsigned int default_hstate_idx;#define default_hstate (hstates[default_hstate_idx]) -static inline struct hstate *hstate_vma (struct vm_area_struct *vma) +static inline struct hstate *hstate_inode (struct inode *i) { -return &default_hstate; +struct hugetlbfs_sb_info *hsb; + hsb =HUGETLBFS_SB (i->i_sb); +return hsb->hstate; }static inline struct hstate *hstate_file (struct file *f) { -return &default_hstate; +return hstate_inode (f->f_dentry->d_inode); } -static inline struct hstate *hstate_inode (struct inode *i) +static inline struct hstate *hstate_vma (struct vm_area_struct *vma) { -return &default_hstate; +return hstate_file (vma->vm_file); }static inline unsigned long huge_page_size (struct hstate *h)
fs/hugetlbfs/inode.c +36 -9
103 lines not on this page · raw message
mm/hugetlb.c +3 -13
@@ -1334,19 +1334,9 @@ void __unmap_hugepage_range(struct vm_arvoid unmap_hugepage_range (struct vm_area_struct *vma,unsigned long start,unsigned long end,struct page *ref_page) { -/* -* It is undesirable to test vma->vm_file as it should be non-null -* for valid hugetlb area. However, vm_file will be NULL in the error -* cleanup path of do_mmap_pgoff. When hugetlbfs ->mmap method fails, -* do_mmap_pgoff() nullifies vma->vm_file before calling this function -* to clean up. Since no pte has actually been setup, it is safe to -* do nothing in this case. -*/ -if (vma->vm_file) { -spin_lock (&vma->vm_file->f_mapping->i_mmap_lock); -__unmap_hugepage_range (vma, start, end, ref_page); -spin_unlock (&vma->vm_file->f_mapping->i_mmap_lock); - } +spin_lock (&vma->vm_file->f_mapping->i_mmap_lock); +__unmap_hugepage_range (vma, start, end, ref_page); +spin_unlock (&vma->vm_file->f_mapping->i_mmap_lock); }/*
mm/memory.c +16 -2
@@ -902,9 +902,23 @@ unsigned long unmap_vmas(struct mmu_gath }if (unlikely (is_vm_hugetlb_page (vma))) { -unmap_hugepage_range (vma, start, end,NULL ); - zap_work -= (end - start) / +/* +* It is undesirable to test vma->vm_file as it +* should be non-null for valid hugetlb area. +* However, vm_file will be NULL in the error +* cleanup path of do_mmap_pgoff. When +* hugetlbfs ->mmap method fails, +* do_mmap_pgoff() nullifies vma->vm_file +* before calling this function to clean up. +* Since no pte has actually been setup, it is +* safe to do nothing in this case. +*/ +if (vma->vm_file) { +unmap_hugepage_range (vma, start, end,NULL ); + zap_work -= (end - start) /pages_per_huge_page (hstate_vma (vma)); + } + start = end; }else start = unmap_page_range(*tlbp, vma,
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 5/21 hugetlb: new sysfs interface
In reply to [email protected]Provide new hugepages user APIs that are more suited to multiple hstates in sysfs. There is a new directory, /sys/kernel/hugepages. Underneath that directory there will be a directory per-supported hugepage size, e.g.:
/sys/kernel/hugepages/hugepages-64kB/sys/kernel/hugepages/hugepages-16384kB/sys/kernel/hugepages/hugepages-16777216kB
corresponding to 64k, 16m and 16g respectively. Within each hugepages-size directory there are a number of files, corresponding to the tracked counters in the hstate, e.g.:
/sys/kernel/hugepages/hugepages-64/nr_hugepages /sys/kernel/hugepages/hugepages-64/nr_overcommit_hugepages /sys/kernel/hugepages/hugepages-64/free_hugepages /sys/kernel/hugepages/hugepages-64/resv_hugepages /sys/kernel/hugepages/hugepages-64/surplus_hugepages
Of these files, the first two are read-write and the latter three are read-only. The size of the hugepage being manipulated is trivially deducible from the enclosing directory and is always expressed in kB (to match meminfo).
---
include/linux/hugetlb.h +2 -0
@@ -164,6 +164,7 @@ unsigned long hugetlb_get_unmapped_area( #ifdef CONFIG_HUGETLB_PAGE +#define HSTATE_NAME_LEN 32 /* Defines one hugetlb page size */ struct hstate { int hugetlb_next_nid;
@@ -179,6 +180,7 @@ struct hstate {unsigned int nr_huge_pages_node[MAX_NUMNODES ];unsigned int free_huge_pages_node[MAX_NUMNODES ];unsigned int surplus_huge_pages_node[MAX_NUMNODES ]; +char name[HSTATE_NAME_LEN ]; };void __init hugetlb_add_hstate (unsigned order);
mm/hugetlb.c +228 -66
312 lines not on this page · raw message
Documentation/ABI/testing/sysfs-kernel-hugepages new file +14 -0
@@ -0,0 +1,14 @@ +What: /sys/kernel/hugepages/ +Date: June 2008 +Contact: Nishanth Aravamudan <[email protected]>, hugetlb maintainers +Description: + /sys/kernel/hugepages/ contains a number of subdirectories + of the form hugepages-<size>kb, where <size> is the page size + of the hugepages supported by the kernel/CPU combination. + + Under these directories are a number of files: + nr_hugepages - minimum number of hugepages reserved + nr_overcommit_hugepages - maximum number that can be allocated + free_hugepages - number of hugepages free + surplus_hugepages - + resv_hugepages -
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 05/21] hugetlb: new sysfs interface
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:44 +1000 [email protected] wrote:
Provide new hugepages user APIs that are more suited to multiple hstates in sysfs. There is a new directory,
/sys/kernel/hugepages. Underneath that directory there will be a directory per-supported hugepage size, e.g.:
/sys/kernel/hugepages/hugepages-64kB/sys/kernel/hugepages/hugepages-16384kB/sys/kernel/hugepages/hugepages-16777216kB
Maybe /sys/mm or /sys/vm would be a more appropriate place.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
Quoted 11 lines · Andrew Morton
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:44 +1000 [email protected] wrote:
Provide new hugepages user APIs that are more suited to multiple hstates in sysfs. There is a new directory,
/sys/kernel/hugepages. Underneath that directory there will be a directory per-supported hugepage size, e.g.:
/sys/kernel/hugepages/hugepages-64kB/sys/kernel/hugepages/hugepages-16384kB/sys/kernel/hugepages/hugepages-16777216kBMaybe
/sys/mmor/sys/vmwould be a more appropriate place.
I'm thinking all the random kernel subsystems under /sys/ should rather be moved to /sys/kernel/. Imagine how much crap will be under the root directory if every kernel subsystem goes there.
The system is the kernel, afterall, the subsystems should be under there (arguably /sys/kernel/mm/hugepages/ would be better again, in fact yes Nish can we do that?).
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
Quoted 13 lines · Nick Piggin
Quoted 11 lines · Andrew Morton
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:44 +1000 [email protected] wrote:
Provide new hugepages user APIs that are more suited to multiple hstates in sysfs. There is a new directory,
/sys/kernel/hugepages. Underneath that directory there will be a directory per-supported hugepage size, e.g.:
/sys/kernel/hugepages/hugepages-64kB/sys/kernel/hugepages/hugepages-16384kB/sys/kernel/hugepages/hugepages-16777216kBMaybe
/sys/mmor/sys/vmwould be a more appropriate place.
Quoted 7 lines
I'm thinking all the random kernel subsystems under
/sys/should rather be moved to/sys/kernel/. Imagine how much crap will be under the root directory if every kernel subsystem goes there.The system is the kernel, afterall, the subsystems should be under there (arguably
/sys/kernel/mm/hugepages/would be better again, in fact yes Nish can we do that?).
It should be pretty easy. Just need to allocate and add an appropriate kobject like kernel_kobj somewhere in the main vm initialization path and then change the parent in my patch to be that one rather than kernel_kobj.
I won't have a chance to do this for a few weeks, though :/
Thanks,
Nish
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
Quoted 12 lines · Nishanth Aravamudan
Quoted 11 lines · Nick Piggin
Quoted 10 lines · Andrew Morton
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:44 +1000 [email protected] wrote:
Provide new hugepages user APIs that are more suited to multiple hstates in sysfs. There is a new directory,
/sys/kernel/hugepages. Underneath that directory there will be a directory per-supported hugepage size, e.g.:
/sys/kernel/hugepages/hugepages-64kB/sys/kernel/hugepages/hugepages-16384kB/sys/kernel/hugepages/hugepages-16777216kB
Quoted 5 lines
Quoted 5 lines
Quoted 1 line
Maybe
/sys/mmor/sys/vmwould be a more appropriate place.I'm thinking all the random kernel subsystems under
/sys/should rather be moved to/sys/kernel/. Imagine how much crap will be under the root directory if every kernel subsystem goes there.
What random subsystems do you see under /sys that are better off under /sys/kernel? Keep in mind, sysfs is an ABI, so moving things is tricky if it's been in a mainline release.
Quoted 8 lines
Quoted 3 lines
The system is the kernel, afterall, the subsystems should be under there (arguably
/sys/kernel/mm/hugepages/would be better again, in fact yes Nish can we do that?).It should be pretty easy. Just need to allocate and add an appropriate kobject like
kernel_kobjsomewhere in the main vm initialization path and then change the parent in my patch to be that one rather thankernel_kobj.
So I'm ready to start doing this, but am curious if you think you'll want to move the other mm-related bits under /sys/kernel/mm too (e.g., /sys/kernel/slab)? If so, then we'll need to plan for it, as it's an ABI change. If not, then we might have mm stuff in different locations.
Thanks,
Nish
Signature · 8 lines
Nishanth Aravamudan <[email protected]> IBM Linux Technology Center -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
In reply to [email protected]This one seems to be causing some compilation errors with SYSFS=n.
Quoted 5 lines
Quoted 5 lines
/scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c: In function '
hugetlb_exit':
/scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:
error: 'hstate_kobjs' undeclared (first use in this function) /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:
Quoted 8 lines
Quoted 8 lines
error: (Each undeclared identifier is reported only once /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:
error: for each function it appears in.) /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1237:
error: 'hugepages_kobj' undeclared (first use in this function) make[2]: *** [mm/hugetlb.o] Error 1
make[1]: *** [mm] Error 2
make: *** [sub-make] Error 2
Should we just move hugetlb_exit() inside the sysfs #ifdef with everything else?
/mm/hugetlb.c renamed from /mm/hugetlb.c.orig +13 -12
@@ -1193,6 +1193,19 @@ h->name); } } + +static void __exit hugetlb_exit(void) +{ +struct hstate *h; + +for_each_hstate (h) { +kobject_put (hstate_kobjs[h - hstates]); + } + +kobject_put (hugepages_kobj); +} +module_exit (hugetlb_exit); +#else static void __init hugetlb_sysfs_init (void ) {
@@ -1226,18 +1239,6 @@ }module_init (hugetlb_init); -static void __exit hugetlb_exit(void) -{ -struct hstate *h; - -for_each_hstate (h) { -kobject_put (hstate_kobjs[h - hstates]); - } - -kobject_put (hugepages_kobj); -} -module_exit (hugetlb_exit); -/* Should be called on processing a hugepagesz=... option */ void __init hugetlb_add_hstate (unsigned order) {
-- Dave
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
Quoted 16 lines · Dave Hansen
This one seems to be causing some compilation errors with SYSFS=n.
Quoted 5 lines
Quoted 5 lines
/scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c: In function '
hugetlb_exit':
/scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:
error: 'hstate_kobjs' undeclared (first use in this function) /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:Quoted 8 lines
Quoted 8 lines
error: (Each undeclared identifier is reported only once /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1234:
error: for each function it appears in.) /scratch/kathys/containers/kernel_trees/upstream/mm/hugetlb.c:1237:
error: 'hugepages_kobj' undeclared (first use in this function) make[2]: *** [mm/hugetlb.o] Error 1
make[1]: *** [mm] Error 2
make: *** [sub-make] Error 2
Quoted 2 lines
Should we just move
hugetlb_exit()inside the sysfs #ifdef with everything else?
Yeah, thanks for testing that (I always forget to testall permutations of these things...)
I think the patch looks fine. Andrew, can you queue it?
Quoted 35 lines
/mm/hugetlb.c renamed from /mm/hugetlb.c.orig +13
-8@@ -1193,6 +1193,19 @@ h->name); } } + +static void __exit hugetlb_exit(void) +{ +struct hstate *h; + +for_each_hstate (h) { +kobject_put (hstate_kobjs[h - hstates]); + } + +kobject_put (hugepages_kobj); +} +module_exit (hugetlb_exit); +#else static void __init hugetlb_sysfs_init (void ) {@@ -1226,18 +1239,6 @@ }module_init (hugetlb_init); -static void __exit hugetlb_exit(void) -{ -struct hstate *h; - -for_each_hstate (h) { -kobject_put (hstate_kobjs[h - hstates]); - } -
/mm/hugetlb.c
Quoted 10 lines
/mm/hugetlb.c renamed from /mm/hugetlb.c.orig +0
-5-kobject_put (hugepages_kobj); -} -module_exit (hugetlb_exit); -/* Should be called on processing a hugepagesz=... option */ void __init hugetlb_add_hstate (unsigned order) { -- Dave
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 05/21] hugetlb: new sysfs interface
Quoted 1 line · On Mon, 23 Jun 2008 04:48:25 +0200 Nick Piggin <[email protected]> wrote:
I think the patch looks fine. Andrew, can you queue it?
uh, yeah, appended. The patch-related backlog appears to number 800-900 emails. It's gonna be a fun week.
btw, I'm rather concerned about -mm's MM changes from you and Rik - I saw a lot of emails go by but it's unclear that there was enough stuff there to get all of this stabilised. Were you paying much attention?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 05/21] hugetlb: new sysfs interface
Quoted 5 lines · Andrew Morton
Quoted 1 line · On Mon, 23 Jun 2008 04:48:25 +0200 Nick Piggin <[email protected]> wrote:
I think the patch looks fine. Andrew, can you queue it?
uh, yeah, appended. The patch-related backlog appears to number 800-900 emails. It's gonna be a fun week.
Good luck with that...
Quoted 3 lines
btw, I'm rather concerned about -mm's MM changes from you and Rik - I saw a lot of emails go by but it's unclear that there was enough stuff there to get all of this stabilised. Were you paying much attention?
As far as I could tell, the lockless pagecache stuff seems pretty good after that first unlock_page fix. It also had an issue with page migration that KOSAKI san fixed. There is an open bug report, but it is against another patchset and doesn't appear to have been a problem in -mm. It may be a reiser4 problem. I'll keep at it, but I don't think it is cause for alarm.
The multiple hugepages set seems fine. Very little noise about it which I guess is thanks in large part to good reviewing from others.
Rik/Lee's patchset seem to be getting rather a bit of noise, but I'm sorry to say I haven't followed or reviewed it much yet.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 6/21 hugetlb: abstract numa round robin selection
In reply to [email protected]Need this as a separate function for a future patch.
No behaviour change.
--- mm/hugetlb.c | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-)
mm/hugetlb.c +22 -15
@@ -383,6 +383,27 @@ static struct page *alloc_fresh_huge_pagreturn page; } +/* +* Use a helper variable to find the next node and then +* copy it back to hugetlb_next_nid afterwards: +* otherwise there's a window in which a racer might +* pass invalid nid MAX_NUMNODES to alloc_pages_node. +* But we don't need to use a spin_lock here: it really +* doesn't matter if occasionally a racer chooses the +* same nid as we do. Move nid forward in the mask even +* if we just successfully allocated a hugepage so that +* the next caller gets hugepages on the next node. +*/ +static int hstate_next_node (struct hstate *h) +{ +int next_nid; + next_nid =next_node (h->hugetlb_next_nid, node_online_map); +if (next_nid ==MAX_NUMNODES ) + next_nid =first_node (node_online_map); + h->hugetlb_next_nid = next_nid; +return next_nid; +} +static int alloc_fresh_huge_page (struct hstate *h) {struct page *page;
@@ -396,21 +417,7 @@ static int alloc_fresh_huge_page(struct page =alloc_fresh_huge_page_node (h, h->hugetlb_next_nid);if (page) ret =1 ; -/* -* Use a helper variable to find the next node and then -* copy it back to hugetlb_next_nid afterwards: -* otherwise there's a window in which a racer might -* pass invalid nid MAX_NUMNODES to alloc_pages_node. -* But we don't need to use a spin_lock here: it really -* doesn't matter if occasionally a racer chooses the -* same nid as we do. Move nid forward in the mask even -* if we just successfully allocated a hugepage so that -* the next caller gets hugepages on the next node. -*/ - next_nid =next_node (h->hugetlb_next_nid, node_online_map); -if (next_nid ==MAX_NUMNODES ) - next_nid =first_node (node_online_map); - h->hugetlb_next_nid = next_nid; + next_nid =hstate_next_node (h); }while (!page && h->hugetlb_next_nid != start_nid);if (ret)
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 7/21 mm: introduce non panic alloc_bootmem
In reply to [email protected]Straight forward variant of the existing __alloc_bootmem_node, only difference is that it doesn't panic on failure. We use this in a subsequent patch when allocating giant hugepages at boot -- don't want to panic if we can't allocate as many as the user asked for.
--- include/linux/bootmem.h | 4 ++++ mm/bootmem.c | 12 ++++++++++++ 2 files changed, 16 insertions(+)
mm/bootmem.c +12 -0
@@ -576,6 +576,18 @@ void * __init alloc_bootmem_section(unsi }#endif +void *__init __alloc_bootmem_node_nopanic (pg_data_t *pgdat,unsigned long size, +unsigned long align,unsigned long goal) +{ +void *ptr; + + ptr =alloc_bootmem_core (pgdat->bdata, size, align, goal,0 ); +if (ptr) +return ptr; + +return __alloc_bootmem_nopanic (size, align, goal); +} +#ifndef ARCH_LOW_ADDRESS_LIMIT #define ARCH_LOW_ADDRESS_LIMIT 0xffffffffUL#endif
include/linux/bootmem.h +4 -0
@@ -87,6 +87,10 @@ extern void *__alloc_bootmem_node(pg_datunsigned long size, unsigned long align, unsigned long goal); +extern void *__alloc_bootmem_node_nopanic (pg_data_t *pgdat, +unsigned long size, +unsigned long align, +unsigned long goal); extern unsigned long init_bootmem_node(pg_data_t *pgdat, unsigned long freepfn, unsigned long startpfn,
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 8/21 mm: export prep_compound_page to mm
In reply to [email protected]hugetlb will need to get compound pages from bootmem to handle the case of them being greater than or equal to MAX_ORDER. Export the constructor function needed for this.
--- mm/internal.h | 2 ++ mm/page_alloc.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-)
mm/internal.h +2 -0
@@ -16,6 +16,8 @@void free_pgtables (struct mmu_gather *tlb,struct vm_area_struct *start_vma,unsigned long floor,unsigned long ceiling); +extern void prep_compound_page (struct page *page,unsigned long order); +static inline void set_page_count (struct page *page,int v) {atomic_set (&page->_count, v);
mm/page_alloc.c +1 -1
@@ -288,7 +288,7 @@ static void free_compound_page(struct pa__free_pages_ok (page,compound_order (page)); } -static void prep_compound_page (struct page *page,unsigned long order) +void prep_compound_page (struct page *page,unsigned long order) {int i;int nr_pages =1 << order;
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 9/21 hugetlb: support larger than MAX_ORDER
In reply to [email protected]This is needed on x86-64 to handle GB pages in hugetlbfs, because it is not practical to enlarge MAX_ORDER to 1GB.
Instead the 1GB pages are only allocated at boot using the bootmem allocator using the hugepages=... option.
These 1G bootmem pages are never freed. In theory it would be possible to implement that with some complications, but since it would be a one-way street (>= MAX_ORDER pages cannot be allocated later) I decided not to currently.
The >= MAX_ORDER code is not ifdef'ed per architecture. It is not very big and the ifdef uglyness seemed not be worth it.
Known problems: /proc/meminfo and "free" do not display the memory allocated for gb pages in "Total". This is a little confusing for the user.
--- mm/hugetlb.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 72 insertions(+), 2 deletions(-)
mm/hugetlb.c +81 -2
@@ -14,6 +14,7 @@#include <linux/mempolicy.h> #include <linux/cpuset.h> #include <linux/mutex.h> +#include <linux/bootmem.h> #include <linux/sysfs.h> #include <asm/page.h>
@@ -307,7 +308,7 @@ static void free_huge_page(struct page *INIT_LIST_HEAD (&page->lru);spin_lock (&hugetlb_lock); -if (h->surplus_huge_pages_node[nid]) { +if (h->surplus_huge_pages_node[nid] &&huge_page_order (h) <MAX_ORDER ) {update_and_free_page (h, page); h->surplus_huge_pages--; h->surplus_huge_pages_node[nid]--;
@@ -368,6 +369,9 @@ static struct page *alloc_fresh_huge_pag {struct page *page; +if (h->order >=MAX_ORDER ) +return NULL ; + page = alloc_pages_node(nid, htlb_alloc_mask|__GFP_COMP|__GFP_THISNODE| __GFP_REPEAT|__GFP_NOWARN,
@@ -434,6 +438,9 @@ static struct page *alloc_buddy_huge_pagstruct page *page;unsigned int nid; +if (h->order >=MAX_ORDER ) +return NULL ; +/* * Assume we will successfully allocate the surplus page to * prevent racing processes from causing the surplus to exceed
@@ -610,6 +617,10 @@ static void return_unused_surplus_pages(/* Uncommit the reservation */ h->resv_huge_pages -= unused_resv_pages; +/* Cannot return gigantic pages currently */ +if (h->order >=MAX_ORDER ) +return ; + nr_pages =min (unused_resv_pages, h->surplus_huge_pages);while (remaining_iterations-- && nr_pages) {
@@ -838,6 +849,63 @@ static struct page *alloc_huge_page(strureturn page; } +static __initdata LIST_HEAD (huge_boot_pages); + +struct huge_bootmem_page { +struct list_head list; +struct hstate *hstate; +}; + +static int __init alloc_bootmem_huge_page (struct hstate *h) +{ +struct huge_bootmem_page *m; +int nr_nodes =nodes_weight (node_online_map); + +while (nr_nodes) { +void *addr; + + addr =__alloc_bootmem_node_nopanic ( +NODE_DATA (h->hugetlb_next_nid), +huge_page_size (h),huge_page_size (h),0 ); + +if (addr) { +/* +* Use the beginning of the huge page to store the +* huge_bootmem_page struct (until gather_bootmem +* puts them into the mem_map). +*/ + m = addr; +if (m) + goto found; + } +hstate_next_node (h); + nr_nodes--; + } +return 0 ; + +found: +BUG_ON ((unsigned long )virt_to_phys (m) & (huge_page_size (h) -1 )); +/* Put them into a private list first because mem_map is not up yet */ +list_add (&m->list, &huge_boot_pages); + m->hstate = h; +return 1 ; +} + +/* Put bootmem huge pages into the standard lists after mem_map is up */ +static void __init gather_bootmem_prealloc (void ) +{ +struct huge_bootmem_page *m; + +list_for_each_entry (m, &huge_boot_pages, list) { +struct page *page =virt_to_page (m); +struct hstate *h = m->hstate; +__ClearPageReserved (page); +WARN_ON (page_count (page) !=1 ); +prep_compound_page (page, h->order); +prep_new_huge_page (h, page,page_to_nid (page)); + } +} +static void __init hugetlb_init_one_hstate (struct hstate *h) {unsigned long i;
@@ -848,7 +916,10 @@ static void __init hugetlb_init_one_hsta h->hugetlb_next_nid =first_node (node_online_map);for (i =0 ; i < h->max_huge_pages; ++i) { -if (!alloc_fresh_huge_page (h)) +if (h->order >=MAX_ORDER ) { +if (!alloc_bootmem_huge_page (h)) +break ; + }else if (!alloc_fresh_huge_page (h))break ; } h->max_huge_pages = h->free_huge_pages = h->nr_huge_pages = i;
@@ -881,6 +952,9 @@ static void try_to_free_low(struct hstat {int i; +if (h->order >=MAX_ORDER ) +return ; +for (i =0 ; i <MAX_NUMNODES ; ++i) {struct page *page, *next;struct list_head *freel = &h->hugepage_freelists[i];
@@ -907,6 +981,9 @@ static unsigned long set_max_huge_pages( {unsigned long min_count, ret; +if (h->order >=MAX_ORDER ) +return h->max_huge_pages; +/* * Increase the pool size * First take pages out of surplus state. Then make up the
@@ -1129,6 +1206,8 @@ static int __init hugetlb_init(void)hugetlb_init_hstates (); +gather_bootmem_prealloc (); +report_hugepages ();hugetlb_sysfs_init ();
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 10/21 hugetlb: support boot allocate different sizes
In reply to [email protected]Make some infrastructure changes to allow boot-time allocation of different hugepage page sizes.
- move all basic hstate initialisation into hugetlb_add_hstate
- create a new function hugetlb_hstate_alloc_pages() to do the actual initial page allocations. Call this function early in order to allocate giant pages from bootmem.
- Check for multiple hugepages= parameters
--- mm/hugetlb.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
mm/hugetlb.c +30 -9
@@ -906,15 +906,10 @@ static void __init gather_bootmem_preall } } -static void __init hugetlb_init_one_hstate (struct hstate *h) +static void __init hugetlb_hstate_alloc_pages (struct hstate *h) {unsigned long i; -for (i =0 ; i <MAX_NUMNODES ; ++i) -INIT_LIST_HEAD (&h->hugepage_freelists[i]); - - h->hugetlb_next_nid =first_node (node_online_map); -for (i =0 ; i < h->max_huge_pages; ++i) {if (h->order >=MAX_ORDER ) {if (!alloc_bootmem_huge_page (h))
@@ -922,7 +917,7 @@ static void __init hugetlb_init_one_hsta }else if (!alloc_fresh_huge_page (h))break ; } - h->max_huge_pages = h->free_huge_pages = h->nr_huge_pages = i; + h->max_huge_pages = i; }static void __init hugetlb_init_hstates (void )
@@ -930,7 +925,9 @@ static void __init hugetlb_init_hstates(struct hstate *h;for_each_hstate (h) { -hugetlb_init_one_hstate (h); +/* oversize hugepages were init'ed in early boot */ +if (h->order <MAX_ORDER ) +hugetlb_hstate_alloc_pages (h); } }
@@ -1232,6 +1229,8 @@ module_exit(hugetlb_exit);void __init hugetlb_add_hstate (unsigned order) {struct hstate *h; +unsigned long i; +if (size_to_hstate (PAGE_SIZE << order)) {printk (KERN_WARNING "hugepagesz= specified twice, ignoring\n" );return ;
@@ -1241,15 +1240,21 @@ void __init hugetlb_add_hstate(unsigned h = &hstates[max_hstate++]; h->order = order; h->mask = ~((1ULL << (order +PAGE_SHIFT )) -1 ); + h->nr_huge_pages =0 ; + h->free_huge_pages =0 ; +for (i =0 ; i <MAX_NUMNODES ; ++i) +INIT_LIST_HEAD (&h->hugepage_freelists[i]); + h->hugetlb_next_nid =first_node (node_online_map);snprintf (h->name,HSTATE_NAME_LEN ,"hugepages-%lukB" ,huge_page_size (h)/1024 ); -hugetlb_init_one_hstate (h); + parsed_hstate = h; }static int __init hugetlb_setup (char *s) {unsigned long *mhp; +static unsigned long *last_mhp;/* * !max_hstate means we haven't parsed a hugepagesz= parameter yet,
@@ -1260,9 +1265,25 @@ static int __init hugetlb_setup(char *s)else mhp = &parsed_hstate->max_huge_pages; +if (mhp == last_mhp) { +printk (KERN_WARNING "hugepages= specified twice without " +"interleaving hugepagesz=, ignoring\n" ); +return 1 ; + } +if (sscanf (s,"%lu" , mhp) <=0 ) *mhp =0 ; +/* +* Global state is always initialized later in hugetlb_init. +* But we need to allocate >= MAX_ORDER hstates here early to still +* use the bootmem allocator. +*/ +if (max_hstate && parsed_hstate->order >=MAX_ORDER ) +hugetlb_hstate_alloc_pages (parsed_hstate); + + last_mhp = mhp; +return 1 ; }__setup ("hugepages=" , hugetlb_setup);
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 11/21 hugetlb: printk cleanup
In reply to [email protected]- Reword sentence to clarify meaning with multiple options
- Add support for using GB prefixes for the page size
- Add extra printk to delayed > MAX_ORDER allocation code
--- mm/hugetlb.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-)
mm/hugetlb.c +16 -4
@@ -931,15 +931,27 @@ static void __init hugetlb_init_hstates( } } +static char *__init memfmt (char *buf,unsigned long n) +{ +if (n >= (1UL <<30 )) +sprintf (buf,"%lu GB" , n >>30 ); +else if (n >= (1UL <<20 )) +sprintf (buf,"%lu MB" , n >>20 ); +else +sprintf (buf,"%lu KB" , n >>10 ); +return buf; +} +static void __init report_hugepages (void ) {struct hstate *h;for_each_hstate (h) { -printk (KERN_INFO "Total HugeTLB memory allocated, " -"%ld %dMB pages\n" , - h->free_huge_pages, -1 << (h->order +PAGE_SHIFT -20 )); +char buf[32 ]; +printk (KERN_INFO "HugeTLB registered %s page size, " +"pre-allocated %ld pages\n" , +memfmt (buf,huge_page_size (h)), + h->free_huge_pages); } }
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 12/21 hugetlb: introduce pud_huge
In reply to [email protected]Straight forward extensions for huge pages located in the PUD instead of PMDs.
--- arch/ia64/mm/hugetlbpage.c | 6 ++++++ arch/powerpc/mm/hugetlbpage.c | 5 +++++ arch/sh/mm/hugetlbpage.c | 5 +++++ arch/sparc64/mm/hugetlbpage.c | 5 +++++ arch/x86/mm/hugetlbpage.c | 25 ++++++++++++++++++++++++- include/linux/hugetlb.h | 5 +++++ mm/hugetlb.c | 9 +++++++++ mm/memory.c | 10 +++++++++- 8 files changed, 68 insertions(+), 2 deletions(-)
include/linux/hugetlb.h +5 -0
@@ -50,7 +50,10 @@ struct page *follow_huge_addr(struct mm_ int write);struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write); +struct page *follow_huge_pud (struct mm_struct *mm,unsigned long address, +pud_t *pud,int write);int pmd_huge (pmd_t pmd); +int pud_huge (pud_t pmd);void hugetlb_change_protection (struct vm_area_struct *vma,unsigned long address,unsigned long end,pgprot_t newprot);
@@ -78,8 +81,10 @@ static inline unsigned long hugetlb_tota#define hugetlb_report_meminfo (buf) 0#define hugetlb_report_node_meminfo (n, buf) 0#define follow_huge_pmd (mm, addr, pmd, write) NULL +#define follow_huge_pud (mm, addr, pud, write) NULL#define prepare_hugepage_range (file, addr, len) (-EINVAL)#define pmd_huge (x) 0 +#define pud_huge (x) 0#define is_hugepage_only_range (mm, addr, len) 0#define hugetlb_free_pgd_range (tlb, addr, end, floor, ceiling) ({BUG(); 0; })#define hugetlb_fault (mm, vma, addr, write) ({ BUG(); 0; })
arch/ia64/mm/hugetlbpage.c +6 -0
@@ -107,6 +107,12 @@ int pmd_huge(pmd_t pmd) {return 0 ; } + +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write) {
arch/powerpc/mm/hugetlbpage.c +5 -0
@@ -369,6 +369,11 @@ int pmd_huge(pmd_t pmd)return 0 ; } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write)
arch/sh/mm/hugetlbpage.c +5 -0
@@ -79,6 +79,11 @@ int pmd_huge(pmd_t pmd)return 0 ; } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write) {
arch/sparc64/mm/hugetlbpage.c +5 -0
@@ -295,6 +295,11 @@ int pmd_huge(pmd_t pmd)return 0 ; } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write) {
arch/x86/mm/hugetlbpage.c +24 -1
@@ -189,6 +189,11 @@ int pmd_huge(pmd_t pmd)return 0 ; } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write)
@@ -209,6 +214,11 @@ int pmd_huge(pmd_t pmd)return !!(pmd_val (pmd) & _PAGE_PSE); } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmd,int write)
@@ -217,9 +227,22 @@ follow_huge_pmd(struct mm_struct *mm, un page =pte_page (*(pte_t *)pmd);if (page) - page += ((address & ~HPAGE_MASK ) >>PAGE_SHIFT ); + page += ((address & ~PMD_MASK ) >>PAGE_SHIFT ); return page; } + +struct page * +follow_huge_pud (struct mm_struct *mm,unsigned long address, +pud_t *pud,int write) +{ +struct page *page; + + page =pte_page (*(pte_t *)pud); +if (page) + page += ((address & ~PUD_MASK ) >>PAGE_SHIFT ); +return page; +} +#endif /* x86_64 also uses this file */
mm/hugetlb.c +9 -0
@@ -1896,6 +1896,15 @@ int hugetlb_fault(struct mm_struct *mm,return ret; } +/* Can be overriden by architectures */ +__attribute__((weak))struct page * +follow_huge_pud (struct mm_struct *mm,unsigned long address, +pud_t *pud,int write) +{ +BUG (); +return NULL ; +} + int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, struct page **pages, struct vm_area_struct **vmas, unsigned long *position, int *length, int i,
mm/memory.c +11 -4
@@ -999,19 +999,24 @@ struct page *follow_page(struct vm_area_ goto no_page_table; pud =pud_offset (pgd, address); -if (pud_none (*pud) ||unlikely (pud_bad (*pud))) +if (pud_none (*pud)) + goto no_page_table; +if (pud_huge (*pud)) { +BUG_ON (flags &FOLL_GET ); + page =follow_huge_pud (mm, address, pud, flags &FOLL_WRITE ); + goto out; + } +if (unlikely (pud_bad (*pud))) goto no_page_table; - + pmd =pmd_offset (pud, address);if (pmd_none (*pmd)) goto no_page_table; -if (pmd_huge (*pmd)) {BUG_ON (flags &FOLL_GET ); page =follow_huge_pmd (mm, address, pmd, flags &FOLL_WRITE ); goto out; } -if (unlikely (pmd_bad (*pmd))) goto no_page_table;
@@ -1542,6 +1547,8 @@ static int apply_to_pmd_range(struct mm_unsigned long next;int err; +BUG_ON (pud_huge (*pud)); + pmd =pmd_alloc (mm, pud, addr);if (!pmd)return -ENOMEM ;
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 12/21] hugetlb: introduce pud_huge
Quoted 2 lines · On Wed, 04 Jun 2008 21:29:51 +1000 [email protected] wrote:
Straight forward extensions for huge pages located in the PUD instead of PMDs.
s390:
mm/built-in.o: In function `follow_page':
: undefined reference to `pud_huge'mm/built-in.o: In function `apply_to_page_range':
: undefined reference to `pud_huge'
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 12/21] hugetlb: introduce pud_huge
Quoted 6 lines · Andrew Morton
Quoted 2 lines · On Wed, 04 Jun 2008 21:29:51 +1000 [email protected] wrote:
Straight forward extensions for huge pages located in the PUD instead of PMDs.
Quoted 6 lines
s390:
mm/built-in.o: In function `follow_page':
: undefined reference to `pud_huge'mm/built-in.o: In function `apply_to_page_range':
: undefined reference to `pud_huge'
Oh, I should have grepped... here:
---
arch/s390/mm/hugetlbpage.c +5 -0
@@ -120,6 +120,11 @@ int pmd_huge(pmd_t pmd)return !!(pmd_val (pmd) & _SEGMENT_ENTRY_LARGE); } +int pud_huge (pud_t pud) +{ +return 0 ; +} +struct page *follow_huge_pmd (struct mm_struct *mm,unsigned long address,pmd_t *pmdp,int write) {
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 13/21 x86: support GB hugepages on 64-bit
In reply to [email protected]--- arch/x86/mm/hugetlbpage.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-)
arch/x86/mm/hugetlbpage.c +22 -11
@@ -134,9 +134,14 @@ pte_t *huge_pte_alloc(struct mm_struct * pgd =pgd_offset (mm, addr); pud =pud_alloc (mm, pgd, addr);if (pud) { -if (pud_none (*pud)) -huge_pmd_share (mm, addr, pud); - pte = (pte_t *)pmd_alloc (mm, pud, addr); +if (sz ==PUD_SIZE ) { + pte = (pte_t *)pud; + }else { +BUG_ON (sz !=PMD_SIZE ); +if (pud_none (*pud)) +huge_pmd_share (mm, addr, pud); + pte = (pte_t *)pmd_alloc (mm, pud, addr); + } }BUG_ON (pte && !pte_none (*pte) && !pte_huge (*pte));
@@ -152,8 +157,11 @@ pte_t *huge_pte_offset(struct mm_struct pgd =pgd_offset (mm, addr);if (pgd_present (*pgd)) { pud =pud_offset (pgd, addr); -if (pud_present (*pud)) +if (pud_present (*pud)) { +if (pud_large (*pud)) +return (pte_t *)pud; pmd =pmd_offset (pud, addr); + } }return (pte_t *) pmd; }
@@ -216,7 +224,7 @@ int pmd_huge(pmd_t pmd)int pud_huge (pud_t pud) { -return 0 ; +return !!(pud_val (pud) & _PAGE_PSE); } struct page *
@@ -252,6 +260,7 @@ static unsigned long hugetlb_get_unmappe unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { + struct hstate *h = hstate_file(file);struct mm_struct *mm = current->mm;struct vm_area_struct *vma;unsigned long start_addr;
@@ -264,7 +273,7 @@ static unsigned long hugetlb_get_unmappe } full_search: - addr =ALIGN (start_addr,HPAGE_SIZE ); + addr =ALIGN (start_addr,huge_page_size (h));for (vma =find_vma (mm, addr); ; vma = vma->vm_next) {/* At this point: (!vma || addr < vma->vm_end). */
@@ -286,7 +295,7 @@ full_search: }if (addr + mm->cached_hole_size < vma->vm_start) mm->cached_hole_size = vma->vm_start - addr; - addr =ALIGN (vma->vm_end,HPAGE_SIZE ); + addr =ALIGN (vma->vm_end,huge_page_size (h)); } }
@@ -294,6 +303,7 @@ static unsigned long hugetlb_get_unmappe unsigned long addr0, unsigned long len, unsigned long pgoff, unsigned long flags) { + struct hstate *h = hstate_file(file);struct mm_struct *mm = current->mm;struct vm_area_struct *vma, *prev_vma;unsigned long base = mm->mmap_base, addr = addr0;
@@ -314,7 +324,7 @@ try_again: goto fail;/* either no address requested or cant fit in requested address hole */ - addr = (mm->free_area_cache - len) &HPAGE_MASK ; + addr = (mm->free_area_cache - len) &huge_page_mask (h); do { /* * Lookup failure means no vma is above this address,
@@ -345,7 +355,7 @@ try_again: largest_hole = vma->vm_start - addr;/* try just below the current vma->vm_start */ - addr = (vma->vm_start - len) &HPAGE_MASK ; + addr = (vma->vm_start - len) &huge_page_mask (h); }while (len <= vma->vm_start); fail:
@@ -383,10 +393,11 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, unsigned long pgoff, unsigned long flags) { + struct hstate *h = hstate_file(file);struct mm_struct *mm = current->mm;struct vm_area_struct *vma; -if (len & ~HPAGE_MASK ) +if (len & ~huge_page_mask (h))return -EINVAL ;if (len >TASK_SIZE )return -ENOMEM ;
@@ -398,7 +409,7 @@ hugetlb_get_unmapped_area(struct file *f }if (addr) { - addr =ALIGN (addr,HPAGE_SIZE ); + addr =ALIGN (addr,huge_page_size (h)); vma =find_vma (mm, addr);if (TASK_SIZE - len >= addr && (!vma || addr + len <= vma->vm_start))
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 14/21 x86: add hugepagesz option on 64-bit
In reply to [email protected]Add an hugepagesz=... option similar to IA64, PPC etc. to x86-64.
This finally allows to select GB pages for hugetlbfs in x86 now that all the infrastructure is in place.
--- Documentation/kernel-parameters.txt | 11 +++++++++-- arch/x86/mm/hugetlbpage.c | 17 +++++++++++++++++ include/asm-x86/page.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-)
arch/x86/mm/hugetlbpage.c +17 -0
@@ -425,3 +425,20 @@ hugetlb_get_unmapped_area(struct file *f#endif /*HAVE_ARCH_HUGETLB_UNMAPPED_AREA*/ +#ifdef CONFIG_X86_64 +static __init int setup_hugepagesz (char *opt) +{ +unsigned long ps =memparse (opt, &opt); +if (ps ==PMD_SIZE ) { +hugetlb_add_hstate (PMD_SHIFT -PAGE_SHIFT ); + }else if (ps ==PUD_SIZE && cpu_has_gbpages) { +hugetlb_add_hstate (PUD_SHIFT -PAGE_SHIFT ); + }else { +printk (KERN_ERR "hugepagesz: Unsupported page size %lu M\n" , + ps >>20 ); +return 0 ; + } +return 1 ; +} +__setup ("hugepagesz=" , setup_hugepagesz); +#endif
include/asm-x86/page.h +2 -0
@@ -29,6 +29,8 @@#define HPAGE_MASK (~(HPAGE_SIZE - 1))#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#define HUGE_MAX_HSTATE 2 +/* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN (addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK)
Documentation/kernel-parameters.txt +9 -2
@@ -765,8 +765,15 @@ and is between 256 and 4096 characters. hisax= [HW,ISDN] See Documentation/isdn/README.HiSax. - hugepages= [HW,X86-32,IA-64] Maximal number of HugeTLB pages. - hugepagesz= [HW,IA-64,PPC] The size of the HugeTLB pages. + hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. + hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. + On x86 this option can be specified multiple times + interleaved with hugepages= to reserve huge pages + of different sizes. Valid pages sizes on x86-64 + are 2M (when the CPU supports "pse") and 1G (when the + CPU supports the "pdpe1gb" cpuinfo flag) + Note that 1GB pages can only be allocated at boot time + using hugepages= and not freed afterwards. i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 14/21] x86: add hugepagesz option on 64-bit
Quoted 18 lines · On Wed, 04 Jun 2008 21:29:53 +1000 [email protected] wrote:
Add an hugepagesz=... option similar to IA64, PPC etc. to x86-64.
This finally allows to select GB pages for hugetlbfs in x86 now that all the infrastructure is in place.
Signed-off-by Andi Kleen <[email protected]>Signed-off-by Nick Piggin <[email protected]>--- Documentation/kernel-parameters.txt | 11 +++++++++-- arch/x86/mm/hugetlbpage.c | 17 +++++++++++++++++ include/asm-x86/page.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. · line 770
Quoted 8 lines
Documentation/kernel-parameters.txt +3
-2@@ -765,8 +765,15 @@ and is between 256 and 4096 characters. hisax= [HW,ISDN] See Documentation/isdn/README.HiSax. - hugepages= [HW,X86-32,IA-64] Maximal number of HugeTLB pages. - hugepagesz= [HW,IA-64,PPC] The size of the HugeTLB pages. + hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. + hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. + On x86 this option can be specified multiple times
Change this x86 to x86-64 like it is both above and below here?
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. · line 774
Quoted 4 lines
Documentation/kernel-parameters.txt +4
-0+ interleaved with hugepages= to reserve huge pages + of different sizes. Valid pages sizes on x86-64 + are 2M (when the CPU supports "pse") and 1G (when the + CPU supports the "pdpe1gb" cpuinfo flag)
flag).
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. · line 779
Quoted 5 lines
Documentation/kernel-parameters.txt +2
-0+ Note that 1GB pages can only be allocated at boot time + using hugepages= and not freed afterwards. i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from
---
~Randy
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 14/21] x86: add hugepagesz option on 64-bit
Quoted 31 lines · Randy Dunlap
Quoted 18 lines · On Wed, 04 Jun 2008 21:29:53 +1000 [email protected] wrote:
Add an hugepagesz=... option similar to IA64, PPC etc. to x86-64.
This finally allows to select GB pages for hugetlbfs in x86 now that all the infrastructure is in place.
Signed-off-by Andi Kleen <[email protected]>Signed-off-by Nick Piggin <[email protected]>--- Documentation/kernel-parameters.txt | 11 +++++++++-- arch/x86/mm/hugetlbpage.c | 17 +++++++++++++++++ include/asm-x86/page.h | 2 ++ 3 files changed, 28 insertions(+), 2 deletions(-)Index:
linux-2.6/Documentation/kernel-parameters.txt
===================================================================Documentation/kernel-parameters.txt and is between 256 and 4096 characters. · line 770
Quoted 8 lines
Documentation/kernel-parameters.txt +3
-2@@ -765,8 +765,15 @@ and is between 256 and 4096 characters. hisax= [HW,ISDN] See Documentation/isdn/README.HiSax. - hugepages= [HW,X86-32,IA-64] Maximal number of HugeTLB pages. - hugepagesz= [HW,IA-64,PPC] The size of the HugeTLB pages. + hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. + hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. + On x86 this option can be specified multiple timesChange this x86 to x86-64 like it is both above and below here?
Quoted 6 lines
Documentation/kernel-parameters.txt and is between 256 and 4096 characters. · line 774
Quoted 4 lines
Documentation/kernel-parameters.txt +4
-0+ interleaved with hugepages= to reserve huge pages + of different sizes. Valid pages sizes on x86-64 + are 2M (when the CPU supports "pse") and 1G (when the + CPU supports the "pdpe1gb" cpuinfo flag)flag).
OK.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 15/21 hugetlb: override default huge page size
In reply to [email protected]Allow configurations with the default huge page size which is different to the traditional HPAGE_SIZE size. The default huge page size is the one represented in the legacy /proc ABIs, SHM, and which is defaulted to when mounting hugetlbfs filesystems.
This is implemented with a new kernel option default_hugepagesz=, which defaults to HPAGE_SIZE if not specified.
--- fs/hugetlbfs/inode.c | 2 ++ mm/hugetlb.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-)
mm/hugetlb.c +18 -7
@@ -34,6 +34,7 @@ struct hstate hstates[HUGE_MAX_HSTATE];/* for command line parsing */ static struct hstate *__initdata parsed_hstate =NULL ;static unsigned long __initdata default_hstate_max_huge_pages =0 ; +static unsigned long __initdata default_hstate_size =HPAGE_SIZE ;#define for_each_hstate (h) \ for ((h) = hstates; (h) < &hstates[max_hstate]; (h)++)
@@ -1207,11 +1208,14 @@ static int __init hugetlb_init(void) {BUILD_BUG_ON (HPAGE_SHIFT ==0 ); -if (!size_to_hstate (HPAGE_SIZE )) { -hugetlb_add_hstate (HUGETLB_PAGE_ORDER ); - parsed_hstate->max_huge_pages = default_hstate_max_huge_pages; - } - default_hstate_idx =size_to_hstate (HPAGE_SIZE ) - hstates; +if (!size_to_hstate (default_hstate_size)) { + default_hstate_size =HPAGE_SIZE ; +if (!size_to_hstate (default_hstate_size)) +hugetlb_add_hstate (HUGETLB_PAGE_ORDER ); + } + default_hstate_idx =size_to_hstate (default_hstate_size) - hstates; +if (default_hstate_max_huge_pages) + default_hstate.max_huge_pages = default_hstate_max_huge_pages;hugetlb_init_hstates ();
@@ -1263,7 +1267,7 @@ void __init hugetlb_add_hstate(unsigned parsed_hstate = h; } -static int __init hugetlb_setup (char *s) +static int __init hugetlb_nrpages_setup (char *s) {unsigned long *mhp;static unsigned long *last_mhp;
@@ -1298,7 +1302,14 @@ static int __init hugetlb_setup(char *s)return 1 ; } -__setup ("hugepages=" , hugetlb_setup); +__setup ("hugepages=" , hugetlb_nrpages_setup); + +static int __init hugetlb_default_setup (char *s) +{ + default_hstate_size =memparse (s, &s); +return 1 ; +} +__setup ("default_hugepagesz=" , hugetlb_default_setup);static unsigned int cpuset_mems_nr (unsigned int *array) {
Documentation/kernel-parameters.txt +7 -0
@@ -774,6 +774,13 @@ and is between 256 and 4096 characters. CPU supports the "pdpe1gb" cpuinfo flag) Note that 1GB pages can only be allocated at boot time using hugepages= and not freed afterwards. + default_hugepagesz= + [same as hugepagesz=] The size of the default + HugeTLB page size. This is the size represented by + the legacy /proc/ hugepages APIs, used for SHM, and + default size when mounting hugetlbfs filesystems. + Defaults to the default architecture's huge page size + if not specified. i8042.direct [HW] Put keyboard port into non-translated mode i8042.dumbkbd [HW] Pretend that controller can only read data from
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 15/21] hugetlb: override default huge page size
Quoted 13 lines · On Wed, 04 Jun 2008 21:29:54 +1000 [email protected] wrote:
Allow configurations with the default huge page size which is different to the traditional
HPAGE_SIZEsize. The default huge page size is the one represented in the legacy /proc ABIs, SHM, and which is defaulted to when mounting hugetlbfs filesystems.This is implemented with a new kernel option default_hugepagesz=, which defaults to
HPAGE_SIZEif not specified....
mm/hugetlb.c struct hstate hstates[HUGE_MAX_HSTATE]; · line 37
Quoted 4 lines
mm/hugetlb.c +1
-0@@ -34,6 +34,7 @@ struct hstate hstates[HUGE_MAX_HSTATE];/* for command line parsing */ static struct hstate *__initdata parsed_hstate =NULL ;static unsigned long __initdata default_hstate_max_huge_pages =0 ; +static unsigned long __initdata default_hstate_size =HPAGE_SIZE ;
ia64:
mm/hugetlb.c:39: error: initializer element is not constant
(wtf?)
Hopefully this'll fix it.
mm/hugetlb.c renamed from mm/hugetlb.c~hugetlb-override-default-huge-page-size-ia64-build +3 -1
@@ -34,7 +34,7 @@ struct hstate hstates[HUGE_MAX_HSTATE];/* for command line parsing */ static struct hstate *__initdata parsed_hstate;static unsigned long __initdata default_hstate_max_huge_pages; -static unsigned long __initdata default_hstate_size =HPAGE_SIZE ; +static unsigned long __initdata default_hstate_size;#define for_each_hstate (h) \ for ((h) = hstates; (h) < &hstates[max_hstate]; (h)++)
@@ -1208,6 +1208,8 @@ static int __init hugetlb_init(void) {BUILD_BUG_ON (HPAGE_SHIFT ==0 ); + default_hstate_size =HPAGE_SIZE ; +if (!size_to_hstate (default_hstate_size)) { default_hstate_size =HPAGE_SIZE ;if (!size_to_hstate (default_hstate_size))
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 15/21] hugetlb: override default huge page size
Quoted 22 lines · Andrew Morton
Quoted 13 lines · On Wed, 04 Jun 2008 21:29:54 +1000 [email protected] wrote:
Allow configurations with the default huge page size which is different to the traditional
HPAGE_SIZEsize. The default huge page size is the one represented in the legacy /proc ABIs, SHM, and which is defaulted to when mounting hugetlbfs filesystems.This is implemented with a new kernel option default_hugepagesz=, which defaults to
HPAGE_SIZEif not specified....
mm/hugetlb.c struct hstate hstates[HUGE_MAX_HSTATE]; · line 37
Quoted 4 lines
mm/hugetlb.c +1
-0@@ -34,6 +34,7 @@ struct hstate hstates[HUGE_MAX_HSTATE];/* for command line parsing */ static struct hstate *__initdata parsed_hstate =NULL ;static unsigned long __initdata default_hstate_max_huge_pages =0 ; +static unsigned long __initdata default_hstate_size =HPAGE_SIZE ;ia64:
Quoted 3 lines
mm/hugetlb.c:39: error: initializer element is not constant(wtf?)
Oh, hmm, despite attempts to hide it behind macros, HPAGE_SHIFT seems like it is boot time configurable.
Quoted 1 line
Hopefully this'll fix it.
It will be fine for the time being, thanks. It actually will break the default hstate size selection (because the parameter parsing code runs first and might want to override default_hstate_size). But don't worry about that, I'll see if I can find a solution for ia64.
Ideally, ia64 will convert HPAGE_SHIFT to their constant HPAGE_SHIFT_DEFAULT, and then implement the new size selection API that this patchset introduces.
But for now, yes, fine, thanks.
Quoted 21 lines
mm/hugetlb.c renamed from mm/hugetlb.c~hugetlb-override-default-huge-page-size-ia64-build +3
-1@@ -34,7 +34,7 @@ struct hstate hstates[HUGE_MAX_HSTATE];/* for command line parsing */ static struct hstate *__initdata parsed_hstate;static unsigned long __initdata default_hstate_max_huge_pages; -static unsigned long __initdata default_hstate_size =HPAGE_SIZE ; +static unsigned long __initdata default_hstate_size;#define for_each_hstate (h) \ for ((h) = hstates; (h) < &hstates[max_hstate]; (h)++)@@ -1208,6 +1208,8 @@ static int __init hugetlb_init(void) {BUILD_BUG_ON (HPAGE_SHIFT ==0 ); + default_hstate_size =HPAGE_SIZE ; +if (!size_to_hstate (default_hstate_size)) { default_hstate_size =HPAGE_SIZE ;if (!size_to_hstate (default_hstate_size))
Quoted 1 line
_
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 16/21 hugetlb: allow arch overried hugepage allocation
In reply to [email protected]Allow alloc_bootmem_huge_page() to be overridden by architectures that can't always use bootmem. This requires huge_boot_pages to be available for use by this function.
This is required for powerpc 16G pages, which have to be reserved prior to boot-time. The location of these pages are indicated in the device tree.
---
include/linux/hugetlb.h | 10 ++++++++++ mm/hugetlb.c | 12 ++++-------- 2 files changed, 14 insertions(+), 8 deletions(-)
include/linux/hugetlb.h +10 -0
@@ -39,6 +39,7 @@ void hugetlb_unreserve_pages(struct inodextern unsigned long hugepages_treat_as_movable;extern const unsigned long hugetlb_zero, hugetlb_infinity;extern int sysctl_hugetlb_shm_group; +extern struct list_head huge_boot_pages;/* arch callbacks */
@@ -188,6 +189,14 @@ struct hstate {char name[HSTATE_NAME_LEN ]; }; +struct huge_bootmem_page { +struct list_head list; +struct hstate *hstate; +}; + +/* arch callback */ +int __init alloc_bootmem_huge_page (struct hstate *h); +void __init hugetlb_add_hstate (unsigned order);struct hstate *size_to_hstate (unsigned long size);
@@ -256,6 +265,7 @@ static inline struct hstate *page_hstate#else struct hstate {}; +#define alloc_bootmem_huge_page (h) NULL#define hstate_file (f) NULL#define hstate_vma (v) NULL#define hstate_inode (i) NULL
mm/hugetlb.c +3 -8
@@ -31,6 +31,8 @@ static int max_hstate = 0;unsigned int default_hstate_idx;struct hstate hstates[HUGE_MAX_HSTATE ]; +__initdata LIST_HEAD (huge_boot_pages); +/* for command line parsing */ static struct hstate *__initdata parsed_hstate =NULL ;static unsigned long __initdata default_hstate_max_huge_pages =0 ;
@@ -850,14 +852,7 @@ static struct page *alloc_huge_page(strureturn page; } -static __initdata LIST_HEAD (huge_boot_pages); - -struct huge_bootmem_page { -struct list_head list; -struct hstate *hstate; -}; - -static int __init alloc_bootmem_huge_page (struct hstate *h) +__attribute__((weak))int alloc_bootmem_huge_page (struct hstate *h) {struct huge_bootmem_page *m;int nr_nodes =nodes_weight (node_online_map);
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 16/21] hugetlb: allow arch overried hugepage allocation
Quoted 1 line · On Wed, 04 Jun 2008 21:29:55 +1000 [email protected] wrote:
Subject: [patch 16/21] hugetlb: allow arch overried hugepage allocation
I assumed that this was supposed to read "overridden".
Quoted 2 lines
+__initdata
LIST_HEAD(huge_boot_pages);
WARNING: externs should be avoided in .c files
#61: FILE: mm/hugetlb.c:34:
+__initdata LIST_HEAD(huge_boot_pages);
checkpatch got confused.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 16/21] hugetlb: allow arch overried hugepage allocation
Quoted 5 lines · Andrew Morton
Quoted 1 line · On Wed, 04 Jun 2008 21:29:55 +1000 [email protected] wrote:
Subject: [patch 16/21] hugetlb: allow arch overried hugepage allocation
I assumed that this was supposed to read "overridden".
Yes.
Quoted 8 lines
Quoted 2 lines
+__initdata
LIST_HEAD(huge_boot_pages);WARNING: externs should be avoided in .c files
#61: FILE:mm/hugetlb.c:34:
+__initdataLIST_HEAD(huge_boot_pages);checkpatch got confused.
I noticed that and forgot to tell anybody :P
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 16/21] hugetlb: allow arch overried hugepage allocation
In reply to Andrew MortonQuoted 7 lines · Andrew Morton
Quoted 1 line · On Wed, 04 Jun 2008 21:29:55 +1000 [email protected] wrote:
Subject: [patch 16/21] hugetlb: allow arch overried hugepage allocation
I assumed that this was supposed to read "overridden".
Quoted 1 line
Quoted 7 lines
Quoted 1 line
+__initdata
LIST_HEAD(huge_boot_pages);WARNING: externs should be avoided in .c files
#61: FILE:mm/hugetlb.c:34:
+__initdataLIST_HEAD(huge_boot_pages);checkpatch got confused.
Yes, I caught that one too. We stupidly convert a known modifier into a type. Sorted in my next block of changes. Will be with you today I hope.
-apw
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 17/21 powerpc: function to allocate gigantic hugepages
In reply to [email protected]The 16G page locations have been saved during early boot in an array. The alloc_bootmem_huge_page() function adds a page from here to the huge_boot_pages list.
---
arch/powerpc/mm/hugetlbpage.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
arch/powerpc/mm/hugetlbpage.c +21 -0
@@ -29,6 +29,12 @@#define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT)#define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT) +#define MAX_NUMBER_GPAGES 1024 + +/* Tracks the 16G pages after the device tree is scanned and before the +* huge_boot_pages list is ready. */ +static unsigned long gpage_freearray[MAX_NUMBER_GPAGES ]; +static unsigned nr_gpages;unsigned int hugepte_shift;#define PTRS_PER_HUGEPTE (1 << hugepte_shift)
@@ -104,6 +110,21 @@ pmd_t *hpmd_alloc(struct mm_struct *mm, }#endif +/* Moves the gigantic page addresses from the temporary list to the +* huge_boot_pages list. */ +int alloc_bootmem_huge_page (struct hstate *h) +{ +struct huge_bootmem_page *m; +if (nr_gpages ==0 ) +return 0 ; + m =phys_to_virt (gpage_freearray[--nr_gpages]); + gpage_freearray[nr_gpages] =0 ; +list_add (&m->list, &huge_boot_pages); + m->hstate = h; +return 1 ; +} + +/* Modelled after find_linux_pte() */ pte_t *huge_pte_offset (struct mm_struct *mm,unsigned long addr) {
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 18/21 powerpc: scan device tree for gigantic pages
In reply to [email protected]The 16G huge pages have to be reserved in the HMC prior to boot. The
location of the pages are placed in the device tree. This patch adds
code to scan the device tree during very early boot and save these page locations until hugetlbfs is ready for them.
---
arch/powerpc/mm/hash_utils_64.c | 44 ++++++++++++++++++++++++++++++++++++++- arch/powerpc/mm/hugetlbpage.c | 16 ++++++++++++++ include/asm-powerpc/mmu-hash64.h | 2 + 3 files changed, 61 insertions(+), 1 deletion(-)
arch/powerpc/mm/hash_utils_64.c +43 -1
@@ -68,6 +68,7 @@#define KB (1024)#define MB (1024*KB) +#define GB (1024L*MB)/* * Note: pte --> Linux PTE
@@ -329,6 +330,44 @@ static int __init htab_dt_scan_page_sizereturn 0 ; } +/* Scan for 16G memory blocks that have been set aside for huge pages +* and reserve those blocks for 16G huge pages. +*/ +static int __init htab_dt_scan_hugepage_blocks (unsigned long node, +const char *uname,int depth, +void *data) { +char *type =of_get_flat_dt_prop (node,"device_type" ,NULL ); +unsigned long *addr_prop; +u32 *page_count_prop; +unsigned int expected_pages; +long unsigned int phys_addr; +long unsigned int block_size; + +/* We are scanning "memory" nodes only */ +if (type ==NULL ||strcmp (type,"memory" ) !=0 ) +return 0 ; + +/* This property is the log base 2 of the number of virtual pages that +* will represent this memory block. */ + page_count_prop =of_get_flat_dt_prop (node,"ibm,expected#pages" ,NULL ); +if (page_count_prop ==NULL ) +return 0 ; + expected_pages = (1 << page_count_prop[0 ]); + addr_prop =of_get_flat_dt_prop (node,"reg" ,NULL ); +if (addr_prop ==NULL ) +return 0 ; + phys_addr = addr_prop[0 ]; + block_size = addr_prop[1 ]; +if (block_size != (16 *GB )) +return 0 ; +printk (KERN_INFO "Huge page(16GB) memory: " +"addr = 0x%lX size = 0x%lX pages = %d\n" , + phys_addr, block_size, expected_pages); +lmb_reserve (phys_addr, block_size * expected_pages); +add_gpage (phys_addr, block_size, expected_pages); +return 0 ; +} +static void __init htab_init_page_sizes (void ) {int rc;
@@ -418,7 +457,10 @@ static void __init htab_init_page_sizes( );#ifdef CONFIG_HUGETLB_PAGE -/* Init large page size. Currently, we pick 16M or 1M depending +/* Reserve 16G huge page memory sections for huge pages */ +of_scan_flat_dt (htab_dt_scan_hugepage_blocks,NULL ); + +/* Init large page size. Currently, we pick 16M or 1M depending * on what is available */ if (mmu_psize_defs[MMU_PAGE_16M ].shift)
arch/powerpc/mm/hugetlbpage.c +16 -0
@@ -110,6 +110,22 @@ pmd_t *hpmd_alloc(struct mm_struct *mm, }#endif +/* Build list of addresses of gigantic pages. This function is used in early +* boot before the buddy or bootmem allocator is setup. +*/ +void add_gpage (unsigned long addr,unsigned long page_size, +unsigned long number_of_pages) +{ +if (!addr) +return ; +while (number_of_pages >0 ) { + gpage_freearray[nr_gpages] = addr; + nr_gpages++; + number_of_pages--; + addr += page_size; + } +} +/* Moves the gigantic page addresses from the temporary list to the * huge_boot_pages list. */ int alloc_bootmem_huge_page (struct hstate *h)
include/asm-powerpc/mmu-hash64.h +2 -0
@@ -281,6 +281,8 @@ extern int htab_bolt_mapping(unsigned lo unsigned long pstart, unsigned long mode, int psize, int ssize);extern void set_huge_psize (int psize); +extern void add_gpage (unsigned long addr,unsigned long page_size, +unsigned long number_of_pages);extern void demote_segment_4k (struct mm_struct *mm,unsigned long addr);extern void htab_initialize (void );
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 19/21 powerpc: define support for 16G hugepages
In reply to [email protected]The huge page size is defined for 16G pages. If a hugepagesz of 16G is specified at boot-time then it becomes the huge page size instead of the default 16M.
The change in pgtable-64K.h is to the macro pte_iterate_hashed_subpages to make the increment to va (the 1 being shifted) be a long so that it is not shifted to 0. Otherwise it would create an infinite loop when the shift value is for a 16G page (when base page size is 64K).
---
arch/powerpc/mm/hugetlbpage.c | 62 ++++++++++++++++++++++++++------------ include/asm-powerpc/pgtable-64k.h | 2 - 2 files changed, 45 insertions(+), 19 deletions(-)
arch/powerpc/mm/hugetlbpage.c +44 -18
@@ -24,8 +24,9 @@#include <asm/cputable.h> #include <asm/spu.h> -#define HPAGE_SHIFT_64K 16 -#define HPAGE_SHIFT_16M 24 +#define PAGE_SHIFT_64K 16 +#define PAGE_SHIFT_16M 24 +#define PAGE_SHIFT_16G 34#define NUM_LOW_AREAS (0x100000000UL >> SID_SHIFT)#define NUM_HIGH_AREAS (PGTABLE_RANGE >> HTLB_AREA_SHIFT)
@@ -95,7 +96,7 @@ static int __hugepte_alloc(struct mm_strstatic inline pmd_t *hpmd_offset (pud_t *pud,unsigned long addr) { -if (HPAGE_SHIFT ==HPAGE_SHIFT_64K ) +if (HPAGE_SHIFT ==PAGE_SHIFT_64K )return pmd_offset (pud, addr);else return (pmd_t *) pud;
@@ -103,7 +104,7 @@ pmd_t *hpmd_offset(pud_t *pud, unsignedstatic inline pmd_t *hpmd_alloc (struct mm_struct *mm,pud_t *pud,unsigned long addr) { -if (HPAGE_SHIFT ==HPAGE_SHIFT_64K ) +if (HPAGE_SHIFT ==PAGE_SHIFT_64K )return pmd_alloc (mm, pud, addr);else return (pmd_t *) pud;
@@ -260,7 +261,7 @@ static void hugetlb_free_pud_range(struccontinue ;hugetlb_free_pmd_range (tlb, pud, addr, next, floor, ceiling);#else -if (HPAGE_SHIFT ==HPAGE_SHIFT_64K ) { +if (HPAGE_SHIFT ==PAGE_SHIFT_64K ) {if (pud_none_or_clear_bad (pud))continue ;hugetlb_free_pmd_range (tlb, pud, addr, next, floor, ceiling);
@@ -591,20 +592,40 @@ void set_huge_psize(int psize) {/* Check that it is a page size supported by the hardware and * that it fits within pagetable limits. */ -if (mmu_psize_defs[psize].shift && mmu_psize_defs[psize].shift <SID_SHIFT && +if (mmu_psize_defs[psize].shift && + mmu_psize_defs[psize].shift <SID_SHIFT_1T && (mmu_psize_defs[psize].shift >MIN_HUGEPTE_SHIFT || - mmu_psize_defs[psize].shift ==HPAGE_SHIFT_64K )) { + mmu_psize_defs[psize].shift ==PAGE_SHIFT_64K || + mmu_psize_defs[psize].shift ==PAGE_SHIFT_16G )) { +/* Return if huge page size is the same as the +* base page size. */ +if (mmu_psize_defs[psize].shift ==PAGE_SHIFT ) +return ; +HPAGE_SHIFT = mmu_psize_defs[psize].shift; mmu_huge_psize = psize; -#ifdef CONFIG_PPC_64K_PAGES - hugepte_shift = (PMD_SHIFT -HPAGE_SHIFT ); -#else -if (HPAGE_SHIFT ==HPAGE_SHIFT_64K ) - hugepte_shift = (PMD_SHIFT -HPAGE_SHIFT ); -else - hugepte_shift = (PUD_SHIFT -HPAGE_SHIFT ); -#endif +switch (HPAGE_SHIFT ) { +case PAGE_SHIFT_64K : +/* We only allow 64k hpages with 4k base page, +* which was checked above, and always put them +* at the PMD */ + hugepte_shift =PMD_SHIFT ; +break ; +case PAGE_SHIFT_16M : +/* 16M pages can be at two different levels +* of pagestables based on base page size */ +if (PAGE_SHIFT ==PAGE_SHIFT_64K ) + hugepte_shift =PMD_SHIFT ; +else /* 4k base page */ + hugepte_shift =PUD_SHIFT ; +break ; +case PAGE_SHIFT_16G : +/* 16G pages are always at PGD level */ + hugepte_shift =PGDIR_SHIFT ; +break ; + } + hugepte_shift -=HPAGE_SHIFT ; }else HPAGE_SHIFT =0 ; }
@@ -620,17 +641,22 @@ static int __init hugepage_setup_sz(char shift =__ffs (size);switch (shift) {#ifndef CONFIG_PPC_64K_PAGES -case HPAGE_SHIFT_64K : +case PAGE_SHIFT_64K : mmu_psize =MMU_PAGE_64K ;break ;#endif -case HPAGE_SHIFT_16M : +case PAGE_SHIFT_16M : mmu_psize =MMU_PAGE_16M ;break ; +case PAGE_SHIFT_16G : + mmu_psize =MMU_PAGE_16G ; +break ; } -if (mmu_psize >=0 && mmu_psize_defs[mmu_psize].shift) +if (mmu_psize >=0 && mmu_psize_defs[mmu_psize].shift) {set_huge_psize (mmu_psize); +hugetlb_add_hstate (shift -PAGE_SHIFT ); + }else printk (KERN_WARNING "Invalid huge page size specified(%llu)\n" , size);
include/asm-powerpc/pgtable-64k.h +1 -1
@@ -125,7 +125,7 @@ static inline struct subpage_prot_tableunsigned __split = (psize ==MMU_PAGE_4K || \ psize ==MMU_PAGE_64K_AP ); \ shift = mmu_psize_defs[psize].shift; \ - for (index = 0; va < __end; index++, va += (1 << shift)) { \ + for (index = 0; va < __end; index++, va += (1L << shift)) { \ if (!__split || __rpte_sub_valid(rpte, index)) do { \ #define pte_iterate_hashed_end() } while(0); } } while(0)
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 19/21] powerpc: define support for 16G hugepages
arch/powerpc/mm/hugetlbpage.c void set_huge_psize(int psize) · line 614
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:58 +1000 [email protected] wrote:
arch/powerpc/mm/hugetlbpage.c +7
-0+switch (HPAGE_SHIFT ) { +case PAGE_SHIFT_64K : +/* We only allow 64k hpages with 4k base page, +* which was checked above, and always put them +* at the PMD */ + hugepte_shift =PMD_SHIFT ; +break ;
eww, what's with the tabspacespacespacespace?
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 19/21] powerpc: define support for 16G hugepages
Quoted 11 lines · Andrew Morton
arch/powerpc/mm/hugetlbpage.c void set_huge_psize(int psize) · line 614
Quoted 7 lines · On Wed, 04 Jun 2008 21:29:58 +1000 [email protected] wrote:
arch/powerpc/mm/hugetlbpage.c +7
-0+switch (HPAGE_SHIFT ) { +case PAGE_SHIFT_64K : +/* We only allow 64k hpages with 4k base page, +* which was checked above, and always put them +* at the PMD */ + hugepte_shift =PMD_SHIFT ; +break ;eww, what's with the tabspacespacespacespace?
Don't think I messed with any of that. There seemed to be some interesting comment styles in that file, so I resisted the urge to change things.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 20/21 fs: check for statfs overflow
In reply to [email protected]Adds a check for an overflow in the filesystem size so if someone is checking with statfs() on a 16G hugetlbfs in a 32bit binary that it will report back EOVERFLOW instead of a size of 0.
---
fs/compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/compat.c +4 -4
@@ -197,8 +197,8 @@ static int put_compat_statfs(struct comp {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */
@@ -271,8 +271,8 @@ out:static int put_compat_statfs64 (struct compat_statfs64 __user *ubuf,struct kstatfs *kbuf) {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */
fs/open.c +2 -1
@@ -63,7 +63,8 @@ static int vfs_statfs_native(struct dentmemcpy (buf, &st,sizeof (st)); else {if (sizeof buf->f_blocks ==4 ) { -if ((st.f_blocks | st.f_bfree | st.f_bavail) & +if ((st.f_blocks | st.f_bfree | st.f_bavail | + st.f_bsize | st.f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/*
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch 20/21] fs: check for statfs overflow
Quoted 3 lines · On Wed, 04 Jun 2008 21:29:59 +1000 [email protected] wrote:
Adds a check for an overflow in the filesystem size so if someone is checking with
statfs()on a 16G hugetlbfs in a 32bit binary that it will report back EOVERFLOW instead of a size of 0.
-ENOUNDERSTAND.
Why won't a 16G filesystem work on a 32-bit binary?
Quoted 51 lines
Signed-off-by Jon Tollefson <[email protected]>Signed-off-by Nick Piggin <[email protected]>---
fs/compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)Index:
linux-2.6/fs/compat.c
===================================================================fs/compat.c +4
-4@@ -197,8 +197,8 @@ static int put_compat_statfs(struct comp {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */ @@ -271,8 +271,8 @@ out:static int put_compat_statfs64 (struct compat_statfs64 __user *ubuf,struct kstatfs *kbuf) {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */ Index:
linux-2.6/fs/open.c
===================================================================fs/open.c +2
-1@@ -63,7 +63,8 @@ static int vfs_statfs_native(struct dentmemcpy (buf, &st,sizeof (st)); else {if (sizeof buf->f_blocks ==4 ) { -if ((st.f_blocks | st.f_bfree | st.f_bavail) & +if ((st.f_blocks | st.f_bfree | st.f_bavail | + st.f_bsize | st.f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* Signature · 1 line
--
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Re: [patch 20/21] fs: check for statfs overflow
Quoted 9 lines · Andrew Morton
Quoted 3 lines · On Wed, 04 Jun 2008 21:29:59 +1000 [email protected] wrote:
Adds a check for an overflow in the filesystem size so if someone is checking with
statfs()on a 16G hugetlbfs in a 32bit binary that it will report back EOVERFLOW instead of a size of 0.
-ENOUNDERSTAND.Why won't a 16G filesystem work on a 32-bit binary?
Well it should work, but if it calls statfs then it will overflow the f_bsize... ah, that should say 16G *block size* hugetlbfs. A 16G hugetlbfs with 2M blocks should work just fine.
Quoted 51 lines
Quoted 51 lines
Signed-off-by Jon Tollefson <[email protected]>Signed-off-by Nick Piggin <[email protected]>---
fs/compat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)Index:
linux-2.6/fs/compat.c
===================================================================fs/compat.c +4
-4@@ -197,8 +197,8 @@ static int put_compat_statfs(struct comp {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */ @@ -271,8 +271,8 @@ out:static int put_compat_statfs64 (struct compat_statfs64 __user *ubuf,struct kstatfs *kbuf) {if (sizeof ubuf->f_blocks ==4 ) { -if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) & -0xffffffff00000000ULL ) +if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail | + kbuf->f_bsize | kbuf->f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/* f_files and f_ffree may be -1; it's okay * to stuff that into 32 bits */ Index:
linux-2.6/fs/open.c
===================================================================fs/open.c +2
-1@@ -63,7 +63,8 @@ static int vfs_statfs_native(struct dentmemcpy (buf, &st,sizeof (st)); else {if (sizeof buf->f_blocks ==4 ) { -if ((st.f_blocks | st.f_bfree | st.f_bavail) & +if ((st.f_blocks | st.f_bfree | st.f_bavail | + st.f_bsize | st.f_frsize) &0xffffffff00000000ULL )return -EOVERFLOW ;/*
Quoted 1 line
Quoted 1 line
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 21/21 powerpc: support multiple hugepage sizes
In reply to [email protected]Instead of using the variable mmu_huge_psize to keep track of the huge page size we use an array of MMU_PAGE_* values. For each supported huge page size we need to know the hugepte_shift value and have a pgtable_cache. The hstate or an mmu_huge_psizes index is passed to functions so that they know which huge page size they should use.
The hugepage sizes 16M and 64K are setup(if available on the hardware) so that they don't have to be set on the boot cmd line in order to use them. The number of 16G pages have to be specified at boot-time though (e.g. hugepagesz=16G hugepages=5).
---
arch/powerpc/mm/hash_utils_64.c | 9 - arch/powerpc/mm/hugetlbpage.c | 272 +++++++++++++++++++++++++-------------- arch/powerpc/mm/init_64.c | 8 - arch/powerpc/mm/tlb_64.c | 2 include/asm-powerpc/hugetlb.h | 5 include/asm-powerpc/mmu-hash64.h | 4 include/asm-powerpc/page_64.h | 1 include/asm-powerpc/pgalloc-64.h | 4 8 files changed, 192 insertions(+), 113 deletions(-)
arch/powerpc/mm/hash_utils_64.c +4 -5
@@ -103,7 +103,6 @@ int mmu_kernel_ssize = MMU_SEGSIZE_256M;int mmu_highuser_ssize =MMU_SEGSIZE_256M ;u16 mmu_slb_size =64 ;#ifdef CONFIG_HUGETLB_PAGE -int mmu_huge_psize =MMU_PAGE_16M ;unsigned int HPAGE_SHIFT ;#endif #ifdef CONFIG_PPC_64K_PAGES
@@ -460,15 +459,15 @@ static void __init htab_init_page_sizes(/* Reserve 16G huge page memory sections for huge pages */ of_scan_flat_dt (htab_dt_scan_hugepage_blocks,NULL ); -/* Init large page size. Currently, we pick 16M or 1M depending +/* Set default large page size. Currently, we pick 16M or 1M depending * on what is available */ if (mmu_psize_defs[MMU_PAGE_16M ].shift) -set_huge_psize (MMU_PAGE_16M ); +HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_16M ].shift;/* With 4k/4level pagetables, we can't (for now) cope with a * huge page size < PMD_SIZE */ else if (mmu_psize_defs[MMU_PAGE_1M ].shift) -set_huge_psize (MMU_PAGE_1M ); +HPAGE_SHIFT = mmu_psize_defs[MMU_PAGE_1M ].shift;#endif /* CONFIG_HUGETLB_PAGE */ }
@@ -871,7 +870,7 @@ int hash_page(unsigned long ea, unsigned#ifdef CONFIG_HUGETLB_PAGE /* Handle hugepage regions */ -if (HPAGE_SHIFT && psize == mmu_huge_psize) { +if (HPAGE_SHIFT && mmu_huge_psizes[psize]) {DBG_LOW (" -> huge page !\n" );return hash_huge_page (mm, access, ea, vsid, local, trap); }
arch/powerpc/mm/hugetlbpage.c +178 -98
558 lines not on this page · raw message
arch/powerpc/mm/init_64.c +4 -4
@@ -153,10 +153,10 @@ static const char *pgtable_cache_name[AR };#ifdef CONFIG_HUGETLB_PAGE -/* Hugepages need one extra cache, initialized in hugetlbpage.c. We -* can't put into the tables above, because HPAGE_SHIFT is not compile -* time constant. */ -struct kmem_cache *pgtable_cache[ARRAY_SIZE (pgtable_cache_size)+1 ]; +/* Hugepages need an extra cache per hugepagesize, initialized in +* hugetlbpage.c. We can't put into the tables above, because HPAGE_SHIFT +* is not compile time constant. */ +struct kmem_cache *pgtable_cache[ARRAY_SIZE (pgtable_cache_size)+MMU_PAGE_COUNT ];#else struct kmem_cache *pgtable_cache[ARRAY_SIZE (pgtable_cache_size)];#endif
arch/powerpc/mm/tlb_64.c +1 -1
@@ -147,7 +147,7 @@ void hpte_need_flush(struct mm_struct *m*/ if (huge) {#ifdef CONFIG_HUGETLB_PAGE - psize = mmu_huge_psize; + psize =get_slice_psize (mm, addr);;#else BUG (); psize =pte_pagesize_index (mm, addr, pte);/* shutup gcc */
include/asm-powerpc/mmu-hash64.h +2 -2
@@ -194,9 +194,9 @@ extern int mmu_ci_restrictions;#ifdef CONFIG_HUGETLB_PAGE /* -* The page size index of the huge pages for use by hugetlbfs +* The page size indexes of the huge pages for use by hugetlbfs */ -extern int mmu_huge_psize; +extern unsigned int mmu_huge_psizes[MMU_PAGE_COUNT ];#endif /* CONFIG_HUGETLB_PAGE */
include/asm-powerpc/page_64.h +1 -0
@@ -90,6 +90,7 @@ extern unsigned int HPAGE_SHIFT;#define HPAGE_SIZE ((1UL) << HPAGE_SHIFT)#define HPAGE_MASK (~(HPAGE_SIZE - 1))#define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT) +#define HUGE_MAX_HSTATE 3#endif /* __ASSEMBLY__ */
include/asm-powerpc/pgalloc-64.h +2 -2
@@ -22,7 +22,7 @@ extern struct kmem_cache *pgtable_cache[#define PUD_CACHE_NUM 1#define PMD_CACHE_NUM 1#define HUGEPTE_CACHE_NUM 2 -#define PTE_NONCACHE_NUM 3/* from GFP rather than kmem_cache */ +#define PTE_NONCACHE_NUM 7/* from GFP rather than kmem_cache */ static inline pgd_t *pgd_alloc (struct mm_struct *mm) {
@@ -119,7 +119,7 @@ static inline void pte_free(struct mm_st__free_page (ptepage); } -#define PGF_CACHENUM_MASK 0x3 +#define PGF_CACHENUM_MASK 0x7 typedef struct pgtable_free { unsigned long val;
include/asm-powerpc/hugetlb.h +3 -2
@@ -24,9 +24,10 @@ pte_t huge_ptep_get_and_clear(struct mm_static inline int prepare_hugepage_range (struct file *file,unsigned long addr,unsigned long len) { -if (len & ~HPAGE_MASK ) +struct hstate *h =hstate_file (file); +if (len & ~huge_page_mask (h))return -EINVAL ; -if (addr & ~HPAGE_MASK ) +if (addr & ~huge_page_mask (h))return -EINVAL ;return 0 ; }
Documentation/kernel-parameters.txt +5 -5
@@ -767,11 +767,11 @@ and is between 256 and 4096 characters. hugepages= [HW,X86-32,IA-64] HugeTLB pages to allocate at boot. hugepagesz= [HW,IA-64,PPC,X86-64] The size of the HugeTLB pages. - On x86 this option can be specified multiple times - interleaved with hugepages= to reserve huge pages - of different sizes. Valid pages sizes on x86-64 - are 2M (when the CPU supports "pse") and 1G (when the - CPU supports the "pdpe1gb" cpuinfo flag) + On x86-64 and powerpc, this option can be specified + multiple times interleaved with hugepages= to reserve + huge pages of different sizes. Valid pages sizes on + x86-64 are 2M (when the CPU supports "pse") and 1G + (when the CPU supports the "pdpe1gb" cpuinfo flag) Note that 1GB pages can only be allocated at boot time using hugepages= and not freed afterwards. default_hugepagesz=
Signature · 5 lines
-- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM, see: http://www.linux-mm.org/ . Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH 1/1 powerpc: hugetlb pgtable cache access cleanup
Cleaned up use of macro. We now reference the pgtable_cache array directly instead of using a macro.
---
arch/powerpc/mm/hugetlbpage.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
arch/powerpc/mm/hugetlbpage.c +11 -11
@@ -53,8 +53,7 @@ unsigned int mmu_huge_psizes[MMU_PAGE_COUNT] = { }; /* initialize all to 0 *//* Subtract one from array size because we don't need a cache for 4K since * is not a huge page size */ -#define huge_pgtable_cache (psize) (pgtable_cache[HUGEPTE_CACHE_NUM \ - + psize-1]) +#define HUGE_PGTABLE_INDEX (psize) (HUGEPTE_CACHE_NUM + psize - 1)#define HUGEPTE_CACHE_NAME (psize) (huge_pgtable_cache_name[psize])static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT ] = {
@@ -113,7 +112,7 @@ static inline pte_t *hugepte_offset(hugepd_t *hpdp, unsigned long addr,static int __hugepte_alloc (struct mm_struct *mm,hugepd_t *hpdp,unsigned long address,unsigned int psize) { -pte_t *new =kmem_cache_alloc (huge_pgtable_cache (psize), +pte_t *new =kmem_cache_alloc (pgtable_cache[HUGE_PGTABLE_INDEX (psize)],GFP_KERNEL |__GFP_REPEAT);if (! new)
@@ -121,7 +120,7 @@ static int __hugepte_alloc(struct mm_struct *mm, hugepd_t *hpdp,spin_lock (&mm->page_table_lock);if (!hugepd_none (*hpdp)) -kmem_cache_free (huge_pgtable_cache (psize), new); +kmem_cache_free (pgtable_cache[HUGE_PGTABLE_INDEX (psize)], new);else hpdp->pd = (unsigned long )new |HUGEPD_OK ;spin_unlock (&mm->page_table_lock);
@@ -751,13 +750,14 @@ static int __init hugetlbpage_init(void)for (psize =0 ; psize <MMU_PAGE_COUNT ; ++psize) {if (mmu_huge_psizes[psize]) { -huge_pgtable_cache (psize) =kmem_cache_create ( -HUGEPTE_CACHE_NAME (psize), -HUGEPTE_TABLE_SIZE (psize), -HUGEPTE_TABLE_SIZE (psize), -0 , - zero_ctor); -if (!huge_pgtable_cache (psize)) + pgtable_cache[HUGE_PGTABLE_INDEX (psize)] = +kmem_cache_create ( +HUGEPTE_CACHE_NAME (psize), +HUGEPTE_TABLE_SIZE (psize), +HUGEPTE_TABLE_SIZE (psize), +0 , + zero_ctor); +if (!pgtable_cache[HUGE_PGTABLE_INDEX (psize)])panic ("hugetlbpage_init(): could not create %s" \"\n" ,HUGEPTE_CACHE_NAME (psize)); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch] powerpc: hugetlb pgtable cache access cleanup
Quoted 1 line · On Mon, 14 Jul 2008 11:32:22 -0500 Jon Tollefson <[email protected]>…
Cleaned up use of macro. We now reference the
pgtable_cachearray directly instead of using a macro.
This clashes rather a lot with all the other hugetlb things which we have queued.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
PATCH v2 1/1 powerpc: hugetlb pgtable cache access cleanup
Quoted 11 lines · Andrew Morton
Quoted 2 lines · On Mon, 14 Jul 2008 11:32:22 -0500 Jon Tollefson <[email protected]>…
Cleaned up use of macro. We now reference the
pgtable_cachearray directly instead of using a macro.This clashes rather a lot with all the other hugetlb things which we have queued.
oops. new version below here should be based on mmotm.
---
Cleaned up use of macro. We now reference the pgtable_cache array directly instead of using a macro.
---
arch/powerpc/mm/hugetlbpage.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
arch/powerpc/mm/hugetlbpage.c +11 -11
@@ -53,8 +53,7 @@/* Subtract one from array size because we don't need a cache for 4K since * is not a huge page size */ -#define huge_pgtable_cache (psize) (pgtable_cache[HUGEPTE_CACHE_NUM \ - + psize-1]) +#define HUGE_PGTABLE_INDEX (psize) (HUGEPTE_CACHE_NUM + psize - 1)#define HUGEPTE_CACHE_NAME (psize) (huge_pgtable_cache_name[psize])static const char *huge_pgtable_cache_name[MMU_PAGE_COUNT ] = {
@@ -113,7 +112,7 @@static int __hugepte_alloc (struct mm_struct *mm,hugepd_t *hpdp,unsigned long address,unsigned int psize) { -pte_t *new =kmem_cache_zalloc (huge_pgtable_cache (psize), +pte_t *new =kmem_cache_zalloc (pgtable_cache[HUGE_PGTABLE_INDEX (psize)],GFP_KERNEL |__GFP_REPEAT);if (! new)
@@ -121,7 +120,7 @@spin_lock (&mm->page_table_lock);if (!hugepd_none (*hpdp)) -kmem_cache_free (huge_pgtable_cache (psize), new); +kmem_cache_free (pgtable_cache[HUGE_PGTABLE_INDEX (psize)], new);else hpdp->pd = (unsigned long )new |HUGEPD_OK ;spin_unlock (&mm->page_table_lock);
@@ -746,13 +745,14 @@for (psize =0 ; psize <MMU_PAGE_COUNT ; ++psize) {if (mmu_huge_psizes[psize]) { -huge_pgtable_cache (psize) =kmem_cache_create ( -HUGEPTE_CACHE_NAME (psize), -HUGEPTE_TABLE_SIZE (psize), -HUGEPTE_TABLE_SIZE (psize), -0 , -NULL ); -if (!huge_pgtable_cache (psize)) + pgtable_cache[HUGE_PGTABLE_INDEX (psize)] = +kmem_cache_create ( +HUGEPTE_CACHE_NAME (psize), +HUGEPTE_TABLE_SIZE (psize), +HUGEPTE_TABLE_SIZE (psize), +0 , +NULL ); +if (!pgtable_cache[HUGE_PGTABLE_INDEX (psize)])panic ("hugetlbpage_init(): could not create %s" \"\n" ,HUGEPTE_CACHE_NAME (psize)); }
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>
Andrew Morton
maintainerRe: [patch v2] powerpc: hugetlb pgtable cache access cleanup
Quoted 5 lines · On Tue, 15 Jul 2008 17:49:38 -0500 Jon Tollefson <[email protected]>…
Quoted 4 lines · Andrew Morton
On Mon, 14 Jul 2008 11:32:22 -0500
Jon Tollefson <[email protected]> wrote:
Quoted 8 lines
Quoted 7 lines
Quoted 2 lines
Cleaned up use of macro. We now reference the
pgtable_cachearray directly instead of using a macro.This clashes rather a lot with all the other hugetlb things which we have queued.
oops. new version below here should be based on mmotm.
Yup, thanks.
Quoted 3 lines
Cleaned up use of macro. We now reference the
pgtable_cachearray directly instead of using a macro.
I queued this after its prerequisites. Once those prerequisites have reached mainline I'll send this patch in to the powerpc maintainers for processing. Unless they ack it and ask me to merge it, which is the least-hassle option.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to [email protected]. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"[email protected]"> [email protected] </a>