ChangeSet 1.2231.1.4, 2005/03/28 19:17:20-08:00, [EMAIL PROTECTED]
[PATCH] ppc64: fix AIO panic on PPC64 caused by is_hugepage_only_range()
When testing AIO on PPC64 (a power5 machine) running 2.6.11 with
CONFIG_HUGETLB_PAGE=y, I ran into a kernel panic when a process exits
that has
done AIO (io_queue_init()) but has not done the io_queue_release(). The
exit_aio() code is cleaning up and panicking when trying to free the
aio ring
buffer.
I tracked this down to is_hugepage_only_range()
(include/asm-ppc64/page.h)
which is doing a touches_hugepage_low_range() which is checking
current->mm->context.htlb_segs. The problem is that exit_mm() cleared
tsk->mm
before doing the mmput() which leads to the exit_aio() and then the
panic.
Looks like is_hugepage_only_range() is only used in ia64 and ppc64.
Fix is to
change is_hugepage_only_range() to take an 'mm' as a parameter as well
as
'addr' and 'len' and then the ppc64 code could change to use 'mm'. It
looks
like it has been broken for quite a while.
Signed-off-by: Daniel McNeil <[EMAIL PROTECTED]>
Acked-by: David Gibson <[EMAIL PROTECTED]>
Acked-by: "Luck, Tony" <[EMAIL PROTECTED]>
Signed-off-by: Andrew Morton <[EMAIL PROTECTED]>
Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
arch/ppc64/mm/hugetlbpage.c | 8 ++++----
include/asm-ia64/page.h | 2 +-
include/asm-ppc64/page.h | 8 ++++----
include/linux/hugetlb.h | 4 ++--
mm/mmap.c | 4 ++--
5 files changed, 13 insertions(+), 13 deletions(-)
diff -Nru a/arch/ppc64/mm/hugetlbpage.c b/arch/ppc64/mm/hugetlbpage.c
--- a/arch/ppc64/mm/hugetlbpage.c 2005-03-28 21:07:06 -08:00
+++ b/arch/ppc64/mm/hugetlbpage.c 2005-03-28 21:07:06 -08:00
@@ -513,7 +513,7 @@
vma = find_vma(mm, addr);
if (((TASK_SIZE - len) >= addr)
&& (!vma || (addr+len) <= vma->vm_start)
- && !is_hugepage_only_range(addr,len))
+ && !is_hugepage_only_range(mm, addr,len))
return addr;
}
start_addr = addr = mm->free_area_cache;
@@ -523,7 +523,7 @@
while (TASK_SIZE - len >= addr) {
BUG_ON(vma && (addr >= vma->vm_end));
- if (touches_hugepage_low_range(addr, len)) {
+ if (touches_hugepage_low_range(mm, addr, len)) {
addr = ALIGN(addr+1, 1<<SID_SHIFT);
vma = find_vma(mm, addr);
continue;
@@ -584,7 +584,7 @@
vma = find_vma(mm, addr);
if (TASK_SIZE - len >= addr &&
(!vma || addr + len <= vma->vm_start)
- && !is_hugepage_only_range(addr,len))
+ && !is_hugepage_only_range(mm, addr,len))
return addr;
}
@@ -597,7 +597,7 @@
addr = (mm->free_area_cache - len) & PAGE_MASK;
do {
hugepage_recheck:
- if (touches_hugepage_low_range(addr, len)) {
+ if (touches_hugepage_low_range(mm, addr, len)) {
addr = (addr & ((~0) << SID_SHIFT)) - len;
goto hugepage_recheck;
} else if (touches_hugepage_high_range(addr, len)) {
diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h 2005-03-28 21:07:06 -08:00
+++ b/include/asm-ia64/page.h 2005-03-28 21:07:06 -08:00
@@ -137,7 +137,7 @@
# define htlbpage_to_page(x) (((unsigned long) REGION_NUMBER(x) << 61)
\
| (REGION_OFFSET(x) >>
(HPAGE_SHIFT-PAGE_SHIFT)))
# define HUGETLB_PAGE_ORDER (HPAGE_SHIFT - PAGE_SHIFT)
-# define is_hugepage_only_range(addr, len) \
+# define is_hugepage_only_range(mm, addr, len) \
(REGION_NUMBER(addr) == REGION_HPAGE && \
REGION_NUMBER((addr)+(len)) == REGION_HPAGE)
extern unsigned int hpage_shift;
diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h 2005-03-28 21:07:06 -08:00
+++ b/include/asm-ppc64/page.h 2005-03-28 21:07:06 -08:00
@@ -48,8 +48,8 @@
#define ARCH_HAS_HUGEPAGE_ONLY_RANGE
#define ARCH_HAS_PREPARE_HUGEPAGE_RANGE
-#define touches_hugepage_low_range(addr, len) \
- (LOW_ESID_MASK((addr), (len)) & current->mm->context.htlb_segs)
+#define touches_hugepage_low_range(mm, addr, len) \
+ (LOW_ESID_MASK((addr), (len)) & mm->context.htlb_segs)
#define touches_hugepage_high_range(addr, len) \
(((addr) > (TASK_HPAGE_BASE-(len))) && ((addr) < TASK_HPAGE_END))
@@ -61,9 +61,9 @@
#define within_hugepage_high_range(addr, len) (((addr) >= TASK_HPAGE_BASE) \
&& ((addr)+(len) <= TASK_HPAGE_END) && ((addr)+(len) >= (addr)))
-#define is_hugepage_only_range(addr, len) \
+#define is_hugepage_only_range(mm, addr, len) \
(touches_hugepage_high_range((addr), (len)) || \
- touches_hugepage_low_range((addr), (len)))
+ touches_hugepage_low_range((mm), (addr), (len)))
#define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
#define in_hugepage_area(context, addr) \
diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h
--- a/include/linux/hugetlb.h 2005-03-28 21:07:06 -08:00
+++ b/include/linux/hugetlb.h 2005-03-28 21:07:06 -08:00
@@ -36,7 +36,7 @@
extern int sysctl_hugetlb_shm_group;
#ifndef ARCH_HAS_HUGEPAGE_ONLY_RANGE
-#define is_hugepage_only_range(addr, len) 0
+#define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
#endif
@@ -71,7 +71,7 @@
#define is_aligned_hugepage_range(addr, len) 0
#define prepare_hugepage_range(addr, len) (-EINVAL)
#define pmd_huge(x) 0
-#define is_hugepage_only_range(addr, len) 0
+#define is_hugepage_only_range(mm, addr, len) 0
#define hugetlb_free_pgtables(tlb, prev, start, end) do { } while (0)
#define alloc_huge_page() ({ NULL; })
#define free_huge_page(p) ({ (void)(p); BUG(); })
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c 2005-03-28 21:07:06 -08:00
+++ b/mm/mmap.c 2005-03-28 21:07:06 -08:00
@@ -1316,7 +1316,7 @@
* reserved hugepage range. For some archs like IA-64,
* there is a separate region for hugepages.
*/
- ret = is_hugepage_only_range(addr, len);
+ ret = is_hugepage_only_range(current->mm, addr, len);
}
if (ret)
return -EINVAL;
@@ -1687,7 +1687,7 @@
unmap_vmas(&tlb, mm, vma, start, end, &nr_accounted, NULL);
vm_unacct_memory(nr_accounted);
- if (is_hugepage_only_range(start, end - start))
+ if (is_hugepage_only_range(mm, start, end - start))
hugetlb_free_pgtables(tlb, prev, start, end);
else
free_pgtables(tlb, prev, start, end);
-
To unsubscribe from this list: send the line "unsubscribe bk-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at http://vger.kernel.org/majordomo-info.html