Re: [PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-31 Thread Andi Kleen
> > +#define overlaps(as, ae, bs, be) ((ae) >= (bs) && (as) <= (be))
> 
> inline function please and a bit more intuituive arrangement of
> arguments.

Which one do you prefer? (to be honest the current one is "intuitive"
to me) 


> 
> > +void __init clear_kernel_mapping(unsigned long address, unsigned long size)
> > +{
> > +   int sh = PMD_SHIFT;
> > +   unsigned long kernel = __pa(__START_KERNEL_map);
> > +
> > +   /*
> > +* Note that we cannot unmap the kernel itself because the unmapped
> > +* holes here are always at least 2MB aligned.
> 
> That's not enforced. The unmap code just does not split pages.

It is -- there are BUG_ONs for this in __clear_kernel_mapping

> 
> > +* This just applies to the trailing areas of the 40MB kernel mapping.
> 
> How is this ensured, that it only affects the end of the 40MB mapping ?

It is enforced in the callers (actually there is only a single caller -- 
the GART code ) by not calling it overlapping for the kernel itself.
Given that could be checked too, but that would be probably overkill
for an internal function.

> 
> > +*/
> > +   if (overlaps(kernel >> sh, (kernel + KERNEL_TEXT_SIZE) >> sh,
> > +   __pa(address) >> sh, __pa(address + size) >> sh)) {
> 
> This checks:
> 
>  (kernel_end + 1) >= gart_start && kernel_start <= gart_end
> 
> One off error:  kernel + KERNEL_TEXT_SIZE 
> needs to be:kernel + KERNEL_TEXT_SIZE - 1

Ok.

> 
> Also there is no sanity check, whether the area is inside real kernel text.

Hmm I can add one, but if that happens the caller is likely seriously
confused and will likely cause other problems anyways. 

I don't think it can happen for the GART code which is currently
the only caller.

> 
> > +   printk(KERN_WARNING
> > +   "Kernel mapping at %lx within 2MB of memory hole\n",
> > +   kernel);
> 
> 
> > +   __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);
> 
> Doh! This is unmapping the wrong place. According to __phys_addr():
> 
>  paddr = vaddr - __START_KERNEL_map + phys_base;

Hmm true -- that will only affect relocatable kernels, but for those
it's wrong. Given that the patch was supposed to fix a case 
that only happens relocatable kernels that's quite ironic :)

Actually thinking about it again you can just drop it for now.
It is orthogonal to gbpages. I think I added it to the series
when I was planning to do kernel mapping as GB pages, but that
turned out to be a bad idea anyways.

Thanks for the review,

-Andi
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-31 Thread Thomas Gleixner
On Tue, 29 Jan 2008, Andi Kleen wrote:
> This was a long standing obscure problem in the relocatable kernel. The
> AMD GART driver needs to unmap part of the GART in the kernel direct mapping 
> to 
> prevent cache corruption. With the relocatable kernel it is in theory 
> possible 
> that the separate kernel text mapping straddles that area too. 
> 
> Normally it should not happen because GART tends to be >= 2GB, and the kernel 
> is normally not loaded that high, but it is possible in theory. 

This smells fishy.

>

>
> +#define overlaps(as, ae, bs, be) ((ae) >= (bs) && (as) <= (be))

inline function please and a bit more intuituive arrangement of
arguments.

> +void __init clear_kernel_mapping(unsigned long address, unsigned long size)
> +{
> + int sh = PMD_SHIFT;
> + unsigned long kernel = __pa(__START_KERNEL_map);
> +
> + /*
> +  * Note that we cannot unmap the kernel itself because the unmapped
> +  * holes here are always at least 2MB aligned.

That's not enforced. The unmap code just does not split pages.

> +  * This just applies to the trailing areas of the 40MB kernel mapping.

How is this ensured, that it only affects the end of the 40MB mapping ?

> +  */
> + if (overlaps(kernel >> sh, (kernel + KERNEL_TEXT_SIZE) >> sh,
> + __pa(address) >> sh, __pa(address + size) >> sh)) {

This checks:

 (kernel_end + 1) >= gart_start && kernel_start <= gart_end

One off error:  kernel + KERNEL_TEXT_SIZE 
needs to be:kernel + KERNEL_TEXT_SIZE - 1

Also there is no sanity check, whether the area is inside real kernel text.

> + printk(KERN_WARNING
> + "Kernel mapping at %lx within 2MB of memory hole\n",
> + kernel);


> + __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);

Doh! This is unmapping the wrong place. According to __phys_addr():

 paddr = vaddr - __START_KERNEL_map + phys_base;

Transformation:

 vaddr = padd + __START_KERNEL_map - phys_base;

Sigh. The clear_kernel_mapping() functionality is just another wreckaged
implementation of CPA.

We really should use CPA and have a function to mark entries not
present. Actually the DEBUG_PAGEALLOC code has one already. There are
sanity checks in the CPA code as well, which can be extended to cover
the GART unmap in a safe way.

Thanks,
tglx
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-31 Thread Thomas Gleixner
On Tue, 29 Jan 2008, Andi Kleen wrote:
 This was a long standing obscure problem in the relocatable kernel. The
 AMD GART driver needs to unmap part of the GART in the kernel direct mapping 
 to 
 prevent cache corruption. With the relocatable kernel it is in theory 
 possible 
 that the separate kernel text mapping straddles that area too. 
 
 Normally it should not happen because GART tends to be = 2GB, and the kernel 
 is normally not loaded that high, but it is possible in theory. 

This smells fishy.




 +#define overlaps(as, ae, bs, be) ((ae) = (bs)  (as) = (be))

inline function please and a bit more intuituive arrangement of
arguments.

 +void __init clear_kernel_mapping(unsigned long address, unsigned long size)
 +{
 + int sh = PMD_SHIFT;
 + unsigned long kernel = __pa(__START_KERNEL_map);
 +
 + /*
 +  * Note that we cannot unmap the kernel itself because the unmapped
 +  * holes here are always at least 2MB aligned.

That's not enforced. The unmap code just does not split pages.

 +  * This just applies to the trailing areas of the 40MB kernel mapping.

How is this ensured, that it only affects the end of the 40MB mapping ?

 +  */
 + if (overlaps(kernel  sh, (kernel + KERNEL_TEXT_SIZE)  sh,
 + __pa(address)  sh, __pa(address + size)  sh)) {

This checks:

 (kernel_end + 1) = gart_start  kernel_start = gart_end

One off error:  kernel + KERNEL_TEXT_SIZE 
needs to be:kernel + KERNEL_TEXT_SIZE - 1

Also there is no sanity check, whether the area is inside real kernel text.

 + printk(KERN_WARNING
 + Kernel mapping at %lx within 2MB of memory hole\n,
 + kernel);


 + __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);

Doh! This is unmapping the wrong place. According to __phys_addr():

 paddr = vaddr - __START_KERNEL_map + phys_base;

Transformation:

 vaddr = padd + __START_KERNEL_map - phys_base;

Sigh. The clear_kernel_mapping() functionality is just another wreckaged
implementation of CPA.

We really should use CPA and have a function to mark entries not
present. Actually the DEBUG_PAGEALLOC code has one already. There are
sanity checks in the CPA code as well, which can be extended to cover
the GART unmap in a safe way.

Thanks,
tglx
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-31 Thread Andi Kleen
  +#define overlaps(as, ae, bs, be) ((ae) = (bs)  (as) = (be))
 
 inline function please and a bit more intuituive arrangement of
 arguments.

Which one do you prefer? (to be honest the current one is intuitive
to me) 


 
  +void __init clear_kernel_mapping(unsigned long address, unsigned long size)
  +{
  +   int sh = PMD_SHIFT;
  +   unsigned long kernel = __pa(__START_KERNEL_map);
  +
  +   /*
  +* Note that we cannot unmap the kernel itself because the unmapped
  +* holes here are always at least 2MB aligned.
 
 That's not enforced. The unmap code just does not split pages.

It is -- there are BUG_ONs for this in __clear_kernel_mapping

 
  +* This just applies to the trailing areas of the 40MB kernel mapping.
 
 How is this ensured, that it only affects the end of the 40MB mapping ?

It is enforced in the callers (actually there is only a single caller -- 
the GART code ) by not calling it overlapping for the kernel itself.
Given that could be checked too, but that would be probably overkill
for an internal function.

 
  +*/
  +   if (overlaps(kernel  sh, (kernel + KERNEL_TEXT_SIZE)  sh,
  +   __pa(address)  sh, __pa(address + size)  sh)) {
 
 This checks:
 
  (kernel_end + 1) = gart_start  kernel_start = gart_end
 
 One off error:  kernel + KERNEL_TEXT_SIZE 
 needs to be:kernel + KERNEL_TEXT_SIZE - 1

Ok.

 
 Also there is no sanity check, whether the area is inside real kernel text.

Hmm I can add one, but if that happens the caller is likely seriously
confused and will likely cause other problems anyways. 

I don't think it can happen for the GART code which is currently
the only caller.

 
  +   printk(KERN_WARNING
  +   Kernel mapping at %lx within 2MB of memory hole\n,
  +   kernel);
 
 
  +   __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);
 
 Doh! This is unmapping the wrong place. According to __phys_addr():
 
  paddr = vaddr - __START_KERNEL_map + phys_base;

Hmm true -- that will only affect relocatable kernels, but for those
it's wrong. Given that the patch was supposed to fix a case 
that only happens relocatable kernels that's quite ironic :)

Actually thinking about it again you can just drop it for now.
It is orthogonal to gbpages. I think I added it to the series
when I was planning to do kernel mapping as GB pages, but that
turned out to be a bad idea anyways.

Thanks for the review,

-Andi
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-28 Thread Andi Kleen

This was a long standing obscure problem in the relocatable kernel. The
AMD GART driver needs to unmap part of the GART in the kernel direct mapping to 
prevent cache corruption. With the relocatable kernel it is in theory possible 
that the separate kernel text mapping straddles that area too. 

Normally it should not happen because GART tends to be >= 2GB, and the kernel 
is normally not loaded that high, but it is possible in theory. 

Teach clear_kernel_mapping() about this case.

This will become more important once the kernel mapping uses 1GB pages.

Cc: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]

Signed-off-by: Andi Kleen <[EMAIL PROTECTED]>

---
 arch/x86/mm/init_64.c |   25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

Index: linux/arch/x86/mm/init_64.c
===
--- linux.orig/arch/x86/mm/init_64.c
+++ linux/arch/x86/mm/init_64.c
@@ -438,7 +438,8 @@ void __init paging_init(void)
  * address and size must be aligned to 2MB boundaries.
  * Does nothing when the mapping doesn't exist.
  */
-void __init clear_kernel_mapping(unsigned long address, unsigned long size)
+static void __init
+__clear_kernel_mapping(unsigned long address, unsigned long size)
 {
unsigned long end = address + size;
 
@@ -475,6 +476,28 @@ void __init clear_kernel_mapping(unsigne
__flush_tlb_all();
 }
 
+#define overlaps(as, ae, bs, be) ((ae) >= (bs) && (as) <= (be))
+
+void __init clear_kernel_mapping(unsigned long address, unsigned long size)
+{
+   int sh = PMD_SHIFT;
+   unsigned long kernel = __pa(__START_KERNEL_map);
+
+   /*
+* Note that we cannot unmap the kernel itself because the unmapped
+* holes here are always at least 2MB aligned.
+* This just applies to the trailing areas of the 40MB kernel mapping.
+*/
+   if (overlaps(kernel >> sh, (kernel + KERNEL_TEXT_SIZE) >> sh,
+   __pa(address) >> sh, __pa(address + size) >> sh)) {
+   printk(KERN_WARNING
+   "Kernel mapping at %lx within 2MB of memory hole\n",
+   kernel);
+   __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);
+   }
+   __clear_kernel_mapping(address, size);
+}
+
 /*
  * Memory hotplug specific functions
  */
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] [1/9] Handle kernel near memory hole in clear_kernel_mapping

2008-01-28 Thread Andi Kleen

This was a long standing obscure problem in the relocatable kernel. The
AMD GART driver needs to unmap part of the GART in the kernel direct mapping to 
prevent cache corruption. With the relocatable kernel it is in theory possible 
that the separate kernel text mapping straddles that area too. 

Normally it should not happen because GART tends to be = 2GB, and the kernel 
is normally not loaded that high, but it is possible in theory. 

Teach clear_kernel_mapping() about this case.

This will become more important once the kernel mapping uses 1GB pages.

Cc: [EMAIL PROTECTED]
Cc: [EMAIL PROTECTED]

Signed-off-by: Andi Kleen [EMAIL PROTECTED]

---
 arch/x86/mm/init_64.c |   25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

Index: linux/arch/x86/mm/init_64.c
===
--- linux.orig/arch/x86/mm/init_64.c
+++ linux/arch/x86/mm/init_64.c
@@ -438,7 +438,8 @@ void __init paging_init(void)
  * address and size must be aligned to 2MB boundaries.
  * Does nothing when the mapping doesn't exist.
  */
-void __init clear_kernel_mapping(unsigned long address, unsigned long size)
+static void __init
+__clear_kernel_mapping(unsigned long address, unsigned long size)
 {
unsigned long end = address + size;
 
@@ -475,6 +476,28 @@ void __init clear_kernel_mapping(unsigne
__flush_tlb_all();
 }
 
+#define overlaps(as, ae, bs, be) ((ae) = (bs)  (as) = (be))
+
+void __init clear_kernel_mapping(unsigned long address, unsigned long size)
+{
+   int sh = PMD_SHIFT;
+   unsigned long kernel = __pa(__START_KERNEL_map);
+
+   /*
+* Note that we cannot unmap the kernel itself because the unmapped
+* holes here are always at least 2MB aligned.
+* This just applies to the trailing areas of the 40MB kernel mapping.
+*/
+   if (overlaps(kernel  sh, (kernel + KERNEL_TEXT_SIZE)  sh,
+   __pa(address)  sh, __pa(address + size)  sh)) {
+   printk(KERN_WARNING
+   Kernel mapping at %lx within 2MB of memory hole\n,
+   kernel);
+   __clear_kernel_mapping(__START_KERNEL_map+__pa(address), size);
+   }
+   __clear_kernel_mapping(address, size);
+}
+
 /*
  * Memory hotplug specific functions
  */
--
To unsubscribe from this list: send the line unsubscribe linux-kernel in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/