Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=c79fb75e5a514a5a35f22c229042aa29f4237e3a
Commit:     c79fb75e5a514a5a35f22c229042aa29f4237e3a
Parent:     348ea204cc23cda35faf962414b674c57da647d7
Author:     Adam Litke <[EMAIL PROTECTED]>
AuthorDate: Wed Nov 14 16:59:38 2007 -0800
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Wed Nov 14 18:45:40 2007 -0800

    hugetlb: fix quota management for private mappings
    
    The hugetlbfs quota management system was never taught to handle MAP_PRIVATE
    mappings when that support was added.  Currently, quota is debited at page
    instantiation and credited at file truncation.  This approach works 
correctly
    for shared pages but is incomplete for private pages.  In addition to
    hugetlb_no_page(), private pages can be instantiated by hugetlb_cow(); but
    this function does not respect quotas.
    
    Private huge pages are treated very much like normal, anonymous pages.  They
    are not "backed" by the hugetlbfs file and are not stored in the mapping's
    radix tree.  This means that private pages are invisible to
    truncate_hugepages() so that function will not credit the quota.
    
    This patch (based on a prototype provided by Ken Chen) moves quota crediting
    for all pages into free_huge_page().  page->private is used to store a 
pointer
    to the mapping to which this page belongs.  This is used to credit quota on
    the appropriate hugetlbfs instance.
    
    Signed-off-by: Adam Litke <[EMAIL PROTECTED]>
    Cc: Ken Chen <[EMAIL PROTECTED]>
    Cc: Ken Chen <[EMAIL PROTECTED]>
    Cc: Andy Whitcroft <[EMAIL PROTECTED]>
    Cc: Dave Hansen <[EMAIL PROTECTED]>
    Cc: David Gibson <[EMAIL PROTECTED]>
    Cc: William Lee Irwin III <[EMAIL PROTECTED]>
    Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 fs/hugetlbfs/inode.c |    1 -
 mm/hugetlb.c         |   13 ++++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
index 12aca8e..6513f56 100644
--- a/fs/hugetlbfs/inode.c
+++ b/fs/hugetlbfs/inode.c
@@ -364,7 +364,6 @@ static void truncate_hugepages(struct inode *inode, loff_t 
lstart)
                        ++next;
                        truncate_huge_page(page);
                        unlock_page(page);
-                       hugetlb_put_quota(mapping);
                        freed++;
                }
                huge_pagevec_release(&pvec);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index f43b3dc..3992bd5 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -116,7 +116,9 @@ static void update_and_free_page(struct page *page)
 static void free_huge_page(struct page *page)
 {
        int nid = page_to_nid(page);
+       struct address_space *mapping;
 
+       mapping = (struct address_space *) page_private(page);
        BUG_ON(page_count(page));
        INIT_LIST_HEAD(&page->lru);
 
@@ -129,6 +131,9 @@ static void free_huge_page(struct page *page)
                enqueue_huge_page(page);
        }
        spin_unlock(&hugetlb_lock);
+       if (mapping)
+               hugetlb_put_quota(mapping);
+       set_page_private(page, 0);
 }
 
 /*
@@ -388,8 +393,10 @@ static struct page *alloc_huge_page(struct vm_area_struct 
*vma,
                page = alloc_huge_page_shared(vma, addr);
        else
                page = alloc_huge_page_private(vma, addr);
-       if (page)
+       if (page) {
                set_page_refcounted(page);
+               set_page_private(page, (unsigned long) vma->vm_file->f_mapping);
+       }
        return page;
 }
 
@@ -730,6 +737,8 @@ static int hugetlb_cow(struct mm_struct *mm, struct 
vm_area_struct *vma,
                set_huge_ptep_writable(vma, address, ptep);
                return 0;
        }
+       if (hugetlb_get_quota(vma->vm_file->f_mapping))
+               return VM_FAULT_SIGBUS;
 
        page_cache_get(old_page);
        new_page = alloc_huge_page(vma, address);
@@ -796,7 +805,6 @@ retry:
                        err = add_to_page_cache(page, mapping, idx, GFP_KERNEL);
                        if (err) {
                                put_page(page);
-                               hugetlb_put_quota(mapping);
                                if (err == -EEXIST)
                                        goto retry;
                                goto out;
@@ -830,7 +838,6 @@ out:
 
 backout:
        spin_unlock(&mm->page_table_lock);
-       hugetlb_put_quota(mapping);
        unlock_page(page);
        put_page(page);
        goto out;
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to