Skip to content

Commit

Permalink
hugetlb: modular state for hugetlb page size
Browse files Browse the repository at this point in the history
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.

[[email protected]: coding-style fixes]
Acked-by: Adam Litke <[email protected]>
Acked-by: Nishanth Aravamudan <[email protected]>
Signed-off-by: Andi Kleen <[email protected]>
Signed-off-by: Nick Piggin <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Andi Kleen authored and torvalds committed Jul 24, 2008
1 parent b7ba30c commit a551643
Show file tree
Hide file tree
Showing 19 changed files with 356 additions and 218 deletions.
7 changes: 4 additions & 3 deletions arch/ia64/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -75,7 +75,8 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
* 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;
Expand Down Expand Up @@ -149,7 +150,7 @@ unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr, u

/* Handle MAP_FIXED */
if (flags & MAP_FIXED) {
if (prepare_hugepage_range(addr, len))
if (prepare_hugepage_range(file, addr, len))
return -EINVAL;
return addr;
}
Expand Down
3 changes: 2 additions & 1 deletion arch/powerpc/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
return 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;
Expand Down
3 changes: 2 additions & 1 deletion arch/s390/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ void arch_release_hugepage(struct page *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;
Expand Down
3 changes: 2 additions & 1 deletion arch/sh/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 3 additions & 2 deletions arch/sparc64/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
return -ENOMEM;

if (flags & MAP_FIXED) {
if (prepare_hugepage_range(addr, len))
if (prepare_hugepage_range(file, addr, len))
return -EINVAL;
return addr;
}
Expand All @@ -195,7 +195,8 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
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;
Expand Down
5 changes: 3 additions & 2 deletions arch/x86/mm/hugetlbpage.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,8 @@ int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
return 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;
Expand Down Expand Up @@ -368,7 +369,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
return -ENOMEM;

if (flags & MAP_FIXED) {
if (prepare_hugepage_range(addr, len))
if (prepare_hugepage_range(file, addr, len))
return -EINVAL;
return addr;
}
Expand Down
52 changes: 30 additions & 22 deletions fs/hugetlbfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
struct inode *inode = file->f_path.dentry->d_inode;
loff_t len, vma_len;
int ret;
struct hstate *h = hstate_file(file);

/*
* vma address alignment (but not the pgoff alignment) has
Expand All @@ -92,7 +93,7 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
vma->vm_ops = &hugetlb_vm_ops;

if (vma->vm_pgoff & ~(HPAGE_MASK >> PAGE_SHIFT))
if (vma->vm_pgoff & ~(huge_page_mask(h) >> PAGE_SHIFT))
return -EINVAL;

vma_len = (loff_t)(vma->vm_end - vma->vm_start);
Expand All @@ -104,8 +105,8 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma)
len = vma_len + ((loff_t)vma->vm_pgoff << PAGE_SHIFT);

if (hugetlb_reserve_pages(inode,
vma->vm_pgoff >> (HPAGE_SHIFT-PAGE_SHIFT),
len >> HPAGE_SHIFT, vma))
vma->vm_pgoff >> huge_page_order(h),
len >> huge_page_shift(h), vma))
goto out;

ret = 0;
Expand All @@ -130,20 +131,21 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
unsigned long start_addr;
struct hstate *h = hstate_file(file);

if (len & ~HPAGE_MASK)
if (len & ~huge_page_mask(h))
return -EINVAL;
if (len > TASK_SIZE)
return -ENOMEM;

if (flags & MAP_FIXED) {
if (prepare_hugepage_range(addr, len))
if (prepare_hugepage_range(file, addr, len))
return -EINVAL;
return addr;
}

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))
Expand All @@ -156,7 +158,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
start_addr = TASK_UNMAPPED_BASE;

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). */
Expand All @@ -174,7 +176,7 @@ hugetlb_get_unmapped_area(struct file *file, unsigned long addr,

if (!vma || addr + len <= vma->vm_start)
return addr;
addr = ALIGN(vma->vm_end, HPAGE_SIZE);
addr = ALIGN(vma->vm_end, huge_page_size(h));
}
}
#endif
Expand Down Expand Up @@ -225,10 +227,11 @@ hugetlbfs_read_actor(struct page *page, unsigned long offset,
static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
size_t len, loff_t *ppos)
{
struct hstate *h = hstate_file(filp);
struct address_space *mapping = filp->f_mapping;
struct inode *inode = mapping->host;
unsigned long index = *ppos >> HPAGE_SHIFT;
unsigned long offset = *ppos & ~HPAGE_MASK;
unsigned long index = *ppos >> huge_page_shift(h);
unsigned long offset = *ppos & ~huge_page_mask(h);
unsigned long end_index;
loff_t isize;
ssize_t retval = 0;
Expand All @@ -243,17 +246,17 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
if (!isize)
goto out;

end_index = (isize - 1) >> HPAGE_SHIFT;
end_index = (isize - 1) >> huge_page_shift(h);
for (;;) {
struct page *page;
int nr, ret;
unsigned long nr, ret;

/* nr is the maximum number of bytes to copy from this page */
nr = HPAGE_SIZE;
nr = huge_page_size(h);
if (index >= end_index) {
if (index > end_index)
goto out;
nr = ((isize - 1) & ~HPAGE_MASK) + 1;
nr = ((isize - 1) & ~huge_page_mask(h)) + 1;
if (nr <= offset) {
goto out;
}
Expand Down Expand Up @@ -287,8 +290,8 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
offset += ret;
retval += ret;
len -= ret;
index += offset >> HPAGE_SHIFT;
offset &= ~HPAGE_MASK;
index += offset >> huge_page_shift(h);
offset &= ~huge_page_mask(h);

if (page)
page_cache_release(page);
Expand All @@ -298,7 +301,7 @@ static ssize_t hugetlbfs_read(struct file *filp, char __user *buf,
break;
}
out:
*ppos = ((loff_t)index << HPAGE_SHIFT) + offset;
*ppos = ((loff_t)index << huge_page_shift(h)) + offset;
mutex_unlock(&inode->i_mutex);
return retval;
}
Expand Down Expand Up @@ -339,8 +342,9 @@ static void truncate_huge_page(struct page *page)

static void truncate_hugepages(struct inode *inode, loff_t lstart)
{
struct hstate *h = hstate_inode(inode);
struct address_space *mapping = &inode->i_data;
const pgoff_t start = lstart >> HPAGE_SHIFT;
const pgoff_t start = lstart >> huge_page_shift(h);
struct pagevec pvec;
pgoff_t next;
int i, freed = 0;
Expand Down Expand Up @@ -449,8 +453,9 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
{
pgoff_t pgoff;
struct address_space *mapping = inode->i_mapping;
struct hstate *h = hstate_inode(inode);

BUG_ON(offset & ~HPAGE_MASK);
BUG_ON(offset & ~huge_page_mask(h));
pgoff = offset >> PAGE_SHIFT;

i_size_write(inode, offset);
Expand All @@ -465,6 +470,7 @@ static int hugetlb_vmtruncate(struct inode *inode, loff_t offset)
static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)
{
struct inode *inode = dentry->d_inode;
struct hstate *h = hstate_inode(inode);
int error;
unsigned int ia_valid = attr->ia_valid;

Expand All @@ -476,7 +482,7 @@ static int hugetlbfs_setattr(struct dentry *dentry, struct iattr *attr)

if (ia_valid & ATTR_SIZE) {
error = -EINVAL;
if (!(attr->ia_size & ~HPAGE_MASK))
if (!(attr->ia_size & ~huge_page_mask(h)))
error = hugetlb_vmtruncate(inode, attr->ia_size);
if (error)
goto out;
Expand Down Expand Up @@ -610,9 +616,10 @@ static int hugetlbfs_set_page_dirty(struct page *page)
static int hugetlbfs_statfs(struct dentry *dentry, struct kstatfs *buf)
{
struct hugetlbfs_sb_info *sbinfo = HUGETLBFS_SB(dentry->d_sb);
struct hstate *h = hstate_inode(dentry->d_inode);

buf->f_type = HUGETLBFS_MAGIC;
buf->f_bsize = HPAGE_SIZE;
buf->f_bsize = huge_page_size(h);
if (sbinfo) {
spin_lock(&sbinfo->stat_lock);
/* If no limits set, just report 0 for max/free/used
Expand Down Expand Up @@ -942,7 +949,8 @@ struct file *hugetlb_file_setup(const char *name, size_t size)
goto out_dentry;

error = -ENOMEM;
if (hugetlb_reserve_pages(inode, 0, size >> HPAGE_SHIFT, NULL))
if (hugetlb_reserve_pages(inode, 0,
size >> huge_page_shift(hstate_inode(inode)), NULL))
goto out_inode;

d_instantiate(dentry, inode);
Expand Down
3 changes: 2 additions & 1 deletion include/asm-ia64/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ void hugetlb_free_pgd_range(struct mmu_gather *tlb, unsigned long addr,
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,
Expand Down
3 changes: 2 additions & 1 deletion include/asm-powerpc/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ pte_t huge_ptep_get_and_clear(struct mm_struct *mm, unsigned long addr,
* 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;
Expand Down
3 changes: 2 additions & 1 deletion include/asm-s390/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ void set_huge_pte_at(struct mm_struct *mm, unsigned long addr,
* 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;
Expand Down
3 changes: 2 additions & 1 deletion include/asm-sh/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ static inline int is_hugepage_only_range(struct mm_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;
Expand Down
3 changes: 2 additions & 1 deletion include/asm-sparc/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ static inline int is_hugepage_only_range(struct mm_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;
Expand Down
8 changes: 5 additions & 3 deletions include/asm-x86/hugetlb.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ static inline int is_hugepage_only_range(struct mm_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)
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;
}
Expand Down
Loading

0 comments on commit a551643

Please sign in to comment.