On Sat, Mar 31, 2012 at 4:07 AM, Chris Metcalf <cmetcalf@xxxxxxxxxx> wrote: > The race is as follows. Suppose a multi-threaded task forks a new > process, thus bumping up the ref count on all the pages. While the fork > is occurring (and thus we have marked all the PTEs as read-only), another > thread in the original process tries to write to a huge page, taking an > access violation from the write-protect and calling hugetlb_cow(). Now, > suppose the fork() fails. It will undo the COW and decrement the ref > count on the pages, so the ref count on the huge page drops back to 1. > Meanwhile hugetlb_cow() also decrements the ref count by one on the > original page, since the original address space doesn't need it any more, > having copied a new page to replace the original page. This leaves the > ref count at zero, and when we call unlock_page(), we panic. > > The solution is to take an extra reference to the page while we are > holding the lock on it. > > Cc: stable@xxxxxxxxxx > Signed-off-by: Chris Metcalf <cmetcalf@xxxxxxxxxx> > --- > mm/hugetlb.c | 8 ++++++-- > 1 files changed, 6 insertions(+), 2 deletions(-) > > diff --git a/mm/hugetlb.c b/mm/hugetlb.c > index 4531be2..ab674fc 100644 > --- a/mm/hugetlb.c > +++ b/mm/hugetlb.c > @@ -2703,8 +2703,10 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma, > * so no worry about deadlock. > */ > page = pte_page(entry); > - if (page != pagecache_page) > + if (page != pagecache_page) { > + get_page(page); > lock_page(page); > + } > Perhaps, directly get page? page = pte_page(entry); + get_page(page); if (page != pagecache_page) lock_page(page); -- To unsubscribe, send a message with 'unsubscribe linux-mm' in the body to majordomo@xxxxxxxxx. For more info on Linux MM, see: http://www.linux-mm.org/ . Fight unfair telecom internet charges in Canada: sign http://stopthemeter.ca/ Don't email: <a href