From 05732657630a045b2f6a917162187d5c4de93dc0 Mon Sep 17 00:00:00 2001 From: Andrew Morton <akpm@digeo.com> Date: Wed, 5 Feb 2003 16:58:19 -0800 Subject: [PATCH] [PATCH] hugetlbfs i_size fixes We're expanding hugetlbfs i_size in the wrong place. If someone attempts to mmap more pages than are available, i_size is updated to reflect the attempted mapping size. So set i_size only when pages are successfully added to the mapping. i_size handling at truncate time is still a bit wrong - if the mapping has pages at (say) page offset 100-200 and the mappng is truncated to (say) page offset 50, i_size should be set to zero. But it is instead set to 50*HPAGE_SIZE. That's harmless. --- arch/i386/mm/hugetlbpage.c | 5 +++++ arch/x86_64/mm/hugetlbpage.c | 6 ++++++ fs/hugetlbfs/inode.c | 5 ----- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c index 8a4d7a782dd2..24ef8785ad12 100644 --- a/arch/i386/mm/hugetlbpage.c +++ b/arch/i386/mm/hugetlbpage.c @@ -284,6 +284,7 @@ void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigne int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) { struct mm_struct *mm = current->mm; + struct inode *inode = mapping->host; unsigned long addr; int ret = 0; @@ -307,6 +308,7 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); page = find_get_page(mapping, idx); if (!page) { + loff_t i_size; page = alloc_hugetlb_page(); if (!page) { ret = -ENOMEM; @@ -318,6 +320,9 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) free_huge_page(page); goto out; } + i_size = (loff_t)(idx + 1) * HPAGE_SIZE; + if (i_size > inode->i_size) + inode->i_size = i_size; } set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); } diff --git a/arch/x86_64/mm/hugetlbpage.c b/arch/x86_64/mm/hugetlbpage.c index 7cf2b510ce03..6cde6a4c0518 100644 --- a/arch/x86_64/mm/hugetlbpage.c +++ b/arch/x86_64/mm/hugetlbpage.c @@ -205,6 +205,7 @@ void zap_hugepage_range(struct vm_area_struct *vma, unsigned long start, unsigne int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) { struct mm_struct *mm = current->mm; + struct inode = mapping->host; unsigned long addr; int ret = 0; @@ -228,6 +229,8 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) + (vma->vm_pgoff >> (HPAGE_SHIFT - PAGE_SHIFT)); page = find_get_page(mapping, idx); if (!page) { + loff_t i_size; + page = alloc_hugetlb_page(); if (!page) { ret = -ENOMEM; @@ -239,6 +242,9 @@ int hugetlb_prefault(struct address_space *mapping, struct vm_area_struct *vma) free_huge_page(page); goto out; } + i_size = (loff_t)(idx + 1) * HPAGE_SIZE; + if (i_size > inode->i_size) + inode->i_size = i_size; } set_huge_pte(mm, vma, page, pte, vma->vm_flags & VM_WRITE); } diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 3c6593928838..ca1027875766 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -45,7 +45,6 @@ static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) { struct inode *inode =file->f_dentry->d_inode; struct address_space *mapping = inode->i_mapping; - size_t len; int ret; if (!capable(CAP_IPC_LOCK)) @@ -66,10 +65,6 @@ 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; ret = hugetlb_prefault(mapping, vma); - len = (vma->vm_end - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT); - if (inode->i_size < len) - inode->i_size = len; - up(&inode->i_sem); return ret; } -- 2.30.9