|
@@ -1942,6 +1942,15 @@ retry:
|
|
lock_page(page);
|
|
lock_page(page);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If we are going to COW a private mapping later, we examine the
|
|
|
|
+ * pending reservations for this page now. This will ensure that
|
|
|
|
+ * any allocations necessary to record that reservation occur outside
|
|
|
|
+ * the spinlock.
|
|
|
|
+ */
|
|
|
|
+ if (write_access && !(vma->vm_flags & VM_SHARED))
|
|
|
|
+ vma_needs_reservation(h, vma, address);
|
|
|
|
+
|
|
spin_lock(&mm->page_table_lock);
|
|
spin_lock(&mm->page_table_lock);
|
|
size = i_size_read(mapping->host) >> huge_page_shift(h);
|
|
size = i_size_read(mapping->host) >> huge_page_shift(h);
|
|
if (idx >= size)
|
|
if (idx >= size)
|
|
@@ -1978,6 +1987,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
pte_t *ptep;
|
|
pte_t *ptep;
|
|
pte_t entry;
|
|
pte_t entry;
|
|
int ret;
|
|
int ret;
|
|
|
|
+ struct page *pagecache_page = NULL;
|
|
static DEFINE_MUTEX(hugetlb_instantiation_mutex);
|
|
static DEFINE_MUTEX(hugetlb_instantiation_mutex);
|
|
struct hstate *h = hstate_vma(vma);
|
|
struct hstate *h = hstate_vma(vma);
|
|
|
|
|
|
@@ -2000,19 +2010,35 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
|
|
|
|
|
|
ret = 0;
|
|
ret = 0;
|
|
|
|
|
|
|
|
+ /*
|
|
|
|
+ * If we are going to COW the mapping later, we examine the pending
|
|
|
|
+ * reservations for this page now. This will ensure that any
|
|
|
|
+ * allocations necessary to record that reservation occur outside the
|
|
|
|
+ * spinlock. For private mappings, we also lookup the pagecache
|
|
|
|
+ * page now as it is used to determine if a reservation has been
|
|
|
|
+ * consumed.
|
|
|
|
+ */
|
|
|
|
+ if (write_access && !pte_write(entry)) {
|
|
|
|
+ vma_needs_reservation(h, vma, address);
|
|
|
|
+
|
|
|
|
+ if (!(vma->vm_flags & VM_SHARED))
|
|
|
|
+ pagecache_page = hugetlbfs_pagecache_page(h,
|
|
|
|
+ vma, address);
|
|
|
|
+ }
|
|
|
|
+
|
|
spin_lock(&mm->page_table_lock);
|
|
spin_lock(&mm->page_table_lock);
|
|
/* Check for a racing update before calling hugetlb_cow */
|
|
/* Check for a racing update before calling hugetlb_cow */
|
|
if (likely(pte_same(entry, huge_ptep_get(ptep))))
|
|
if (likely(pte_same(entry, huge_ptep_get(ptep))))
|
|
- if (write_access && !pte_write(entry)) {
|
|
|
|
- struct page *page;
|
|
|
|
- page = hugetlbfs_pagecache_page(h, vma, address);
|
|
|
|
- ret = hugetlb_cow(mm, vma, address, ptep, entry, page);
|
|
|
|
- if (page) {
|
|
|
|
- unlock_page(page);
|
|
|
|
- put_page(page);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ if (write_access && !pte_write(entry))
|
|
|
|
+ ret = hugetlb_cow(mm, vma, address, ptep, entry,
|
|
|
|
+ pagecache_page);
|
|
spin_unlock(&mm->page_table_lock);
|
|
spin_unlock(&mm->page_table_lock);
|
|
|
|
+
|
|
|
|
+ if (pagecache_page) {
|
|
|
|
+ unlock_page(pagecache_page);
|
|
|
|
+ put_page(pagecache_page);
|
|
|
|
+ }
|
|
|
|
+
|
|
mutex_unlock(&hugetlb_instantiation_mutex);
|
|
mutex_unlock(&hugetlb_instantiation_mutex);
|
|
|
|
|
|
return ret;
|
|
return ret;
|