2005-03-09 23:50:06

by Jeff Dike

[permalink] [raw]
Subject: [PATCH 9/9] UML - Fix rounding bug in tlb flushing

From: Bodo Stroesser <[email protected]>

fix_range_common and flush_tlb_kernel_range_common don't work correctly,
if a PGD (or PUD or PMD) is not present and start_addr (resp. start) is not
aligned to a PGD boundary (or PUD or PMD boundary).

Signed-off-by: Bodo Stroesser <[email protected]>
Signed-off-by: Jeff Dike <[email protected]>

Index: linux-2.6.11/arch/um/kernel/tlb.c
===================================================================
--- linux-2.6.11.orig/arch/um/kernel/tlb.c 2005-03-08 23:46:28.000000000 -0500
+++ linux-2.6.11/arch/um/kernel/tlb.c 2005-03-09 00:03:30.000000000 -0500
@@ -15,6 +15,8 @@
#include "mem_user.h"
#include "os.h"

+#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
+
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force, int data,
void (*do_ops)(int, struct host_vm_op *, int))
@@ -33,46 +35,46 @@
for(addr = start_addr; addr < end_addr;){
npgd = pgd_offset(mm, addr);
if(!pgd_present(*npgd)){
+ end = ADD_ROUND(addr, PGDIR_SIZE);
+ if(end > end_addr)
+ end = end_addr;
if(force || pgd_newpage(*npgd)){
- end = addr + PGDIR_SIZE;
- if(end > end_addr)
- end = end_addr;
op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data,
do_ops);
pgd_mkuptodate(*npgd);
}
- addr += PGDIR_SIZE;
+ addr = end;
continue;
}

npud = pud_offset(npgd, addr);
if(!pud_present(*npud)){
+ end = ADD_ROUND(addr, PUD_SIZE);
+ if(end > end_addr)
+ end = end_addr;
if(force || pud_newpage(*npud)){
- end = addr + PUD_SIZE;
- if(end > end_addr)
- end = end_addr;
op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data,
do_ops);
pud_mkuptodate(*npud);
}
- addr += PUD_SIZE;
+ addr = end;
continue;
}

npmd = pmd_offset(npud, addr);
if(!pmd_present(*npmd)){
+ end = ADD_ROUND(addr, PMD_SIZE);
+ if(end > end_addr)
+ end = end_addr;
if(force || pmd_newpage(*npmd)){
- end = addr + PMD_SIZE;
- if(end > end_addr)
- end = end_addr;
op_index = add_munmap(addr, end - addr, ops,
op_index, last_op, data,
do_ops);
pmd_mkuptodate(*npmd);
}
- addr += PMD_SIZE;
+ addr = end;
continue;
}

@@ -122,52 +124,52 @@
for(addr = start; addr < end;){
pgd = pgd_offset(mm, addr);
if(!pgd_present(*pgd)){
+ last = ADD_ROUND(addr, PGDIR_SIZE);
+ if(last > end)
+ last = end;
if(pgd_newpage(*pgd)){
updated = 1;
- last = addr + PGDIR_SIZE;
- if(last > end)
- last = end;
err = os_unmap_memory((void *) addr,
last - addr);
if(err < 0)
panic("munmap failed, errno = %d\n",
-err);
}
- addr += PGDIR_SIZE;
+ addr = last;
continue;
}

pud = pud_offset(pgd, addr);
if(!pud_present(*pud)){
+ last = ADD_ROUND(addr, PUD_SIZE);
+ if(last > end)
+ last = end;
if(pud_newpage(*pud)){
updated = 1;
- last = addr + PUD_SIZE;
- if(last > end)
- last = end;
err = os_unmap_memory((void *) addr,
last - addr);
if(err < 0)
panic("munmap failed, errno = %d\n",
-err);
}
- addr += PUD_SIZE;
+ addr = last;
continue;
}

pmd = pmd_offset(pud, addr);
if(!pmd_present(*pmd)){
+ last = ADD_ROUND(addr, PMD_SIZE);
+ if(last > end)
+ last = end;
if(pmd_newpage(*pmd)){
updated = 1;
- last = addr + PMD_SIZE;
- if(last > end)
- last = end;
err = os_unmap_memory((void *) addr,
last - addr);
if(err < 0)
panic("munmap failed, errno = %d\n",
-err);
}
- addr += PMD_SIZE;
+ addr = last;
continue;
}