Commit eba29972 authored by Linus Torvalds's avatar Linus Torvalds

Fix double unlock of page_table_lock in do_wp_page().

Noticed by Petr Vandrovec.

In the out-of-memory case, do_wp_page() would unlock page_table_lock
twice - once before allocating, and once in the exit path.

Rewrite the exit paths to be more readable, and don't try to share
the code between all the exit cases, since they are very different. 
parent eda7aa60
...@@ -1001,8 +1001,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1001,8 +1001,7 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
{ {
struct page *old_page, *new_page; struct page *old_page, *new_page;
unsigned long pfn = pte_pfn(pte); unsigned long pfn = pte_pfn(pte);
struct pte_chain *pte_chain = NULL; struct pte_chain *pte_chain;
int ret;
if (unlikely(!pfn_valid(pfn))) { if (unlikely(!pfn_valid(pfn))) {
/* /*
...@@ -1013,7 +1012,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1013,7 +1012,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
pte_unmap(page_table); pte_unmap(page_table);
printk(KERN_ERR "do_wp_page: bogus page at address %08lx\n", printk(KERN_ERR "do_wp_page: bogus page at address %08lx\n",
address); address);
goto oom; spin_unlock(&mm->page_table_lock);
return VM_FAULT_OOM;
} }
old_page = pfn_to_page(pfn); old_page = pfn_to_page(pfn);
...@@ -1025,8 +1025,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1025,8 +1025,8 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
establish_pte(vma, address, page_table, establish_pte(vma, address, page_table,
pte_mkyoung(pte_mkdirty(pte_mkwrite(pte)))); pte_mkyoung(pte_mkdirty(pte_mkwrite(pte))));
pte_unmap(page_table); pte_unmap(page_table);
ret = VM_FAULT_MINOR; spin_unlock(&mm->page_table_lock);
goto out; return VM_FAULT_MINOR;
} }
} }
pte_unmap(page_table); pte_unmap(page_table);
...@@ -1039,10 +1039,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1039,10 +1039,10 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
pte_chain = pte_chain_alloc(GFP_KERNEL); pte_chain = pte_chain_alloc(GFP_KERNEL);
if (!pte_chain) if (!pte_chain)
goto no_mem; goto no_pte_chain;
new_page = alloc_page(GFP_HIGHUSER); new_page = alloc_page(GFP_HIGHUSER);
if (!new_page) if (!new_page)
goto no_mem; goto no_new_page;
copy_cow_page(old_page,new_page,address); copy_cow_page(old_page,new_page,address);
/* /*
...@@ -1064,17 +1064,15 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma, ...@@ -1064,17 +1064,15 @@ static int do_wp_page(struct mm_struct *mm, struct vm_area_struct * vma,
pte_unmap(page_table); pte_unmap(page_table);
page_cache_release(new_page); page_cache_release(new_page);
page_cache_release(old_page); page_cache_release(old_page);
ret = VM_FAULT_MINOR;
goto out;
no_mem:
page_cache_release(old_page);
oom:
ret = VM_FAULT_OOM;
out:
spin_unlock(&mm->page_table_lock); spin_unlock(&mm->page_table_lock);
pte_chain_free(pte_chain); pte_chain_free(pte_chain);
return ret; return VM_FAULT_MINOR;
no_new_page:
pte_chain_free(pte_chain);
no_pte_chain:
page_cache_release(old_page);
return VM_FAULT_OOM;
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment