2008-06-18 08:27:55

by Jan Beulich

[permalink] [raw]
Subject: agp: two-stage page destruction issue

Dave,

besides it apparently being useful only in 2.6.24 (the changes in 2.6.25
really mean that it could be converted back to a single-stage mechanism),
I'm seeing an issue in Xen Dom0 kernels, which is caused by the calling
of gart_to_virt() in the second stage invocations of the destroy function.
I think that besides this being a real issue with Xen (where
unmap_page_from_agp() is not just a page table attribute change), this
also is invalid from a theoretical perspective: One should not assume that
gart_to_virt() is still valid after unmapping a page. So minimally (keeping
the 2-stage mechanism) a patch like the one below would be needed.

Jan

--- a/drivers/char/agp/backend.c
+++ b/drivers/char/agp/backend.c
@@ -188,10 +188,10 @@ static int agp_backend_initialize(struct

err_out:
if (bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_UNMAP);
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_FREE);
+ void *va = gart_to_virt(bridge->scratch_page_real);
+
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
if (got_gatt)
bridge->driver->free_gatt_table(bridge);
@@ -215,10 +215,10 @@ static void agp_backend_cleanup(struct a

if (bridge->driver->agp_destroy_page &&
bridge->driver->needs_scratch_page) {
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_UNMAP);
- bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
- AGP_PAGE_DESTROY_FREE);
+ void *va = gart_to_virt(bridge->scratch_page_real);
+
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
+ bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
}
}

--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -202,10 +202,13 @@ void agp_free_memory(struct agp_memory *
}
if (curr->page_count != 0) {
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
+ curr->memory[i] = (unsigned long)gart_to_virt(curr->memory[i]);
+ curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
+ AGP_PAGE_DESTROY_UNMAP);
}
for (i = 0; i < curr->page_count; i++) {
- curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
+ curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
+ AGP_PAGE_DESTROY_FREE);
}
}
agp_free_key(curr->key);
--- a/drivers/char/agp/intel-agp.c
+++ b/drivers/char/agp/intel-agp.c
@@ -428,9 +428,11 @@ static void intel_i810_free_by_type(stru
if (curr->page_count == 4)
i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
else {
- agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ void *va = gart_to_virt(curr->memory[0]);
+
+ agp_bridge->driver->agp_destroy_page(va,
AGP_PAGE_DESTROY_UNMAP);
- agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
+ agp_bridge->driver->agp_destroy_page(va,
AGP_PAGE_DESTROY_FREE);
}
agp_free_page_array(curr);


2008-06-18 23:57:51

by Dave Airlie

[permalink] [raw]
Subject: Re: agp: two-stage page destruction issue

On Wed, Jun 18, 2008 at 6:28 PM, Jan Beulich <[email protected]> wrote:
> Dave,
>
> besides it apparently being useful only in 2.6.24 (the changes in 2.6.25
> really mean that it could be converted back to a single-stage mechanism),
> I'm seeing an issue in Xen Dom0 kernels, which is caused by the calling
> of gart_to_virt() in the second stage invocations of the destroy function.
> I think that besides this being a real issue with Xen (where
> unmap_page_from_agp() is not just a page table attribute change), this
> also is invalid from a theoretical perspective: One should not assume that
> gart_to_virt() is still valid after unmapping a page. So minimally (keeping
> the 2-stage mechanism) a patch like the one below would be needed.
>

Looks good to me, its the simpler change for 2.6.26 at this point.

Dave.

> Jan
>
> --- a/drivers/char/agp/backend.c
> +++ b/drivers/char/agp/backend.c
> @@ -188,10 +188,10 @@ static int agp_backend_initialize(struct
>
> err_out:
> if (bridge->driver->needs_scratch_page) {
> - bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
> - AGP_PAGE_DESTROY_UNMAP);
> - bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
> - AGP_PAGE_DESTROY_FREE);
> + void *va = gart_to_virt(bridge->scratch_page_real);
> +
> + bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
> + bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
> }
> if (got_gatt)
> bridge->driver->free_gatt_table(bridge);
> @@ -215,10 +215,10 @@ static void agp_backend_cleanup(struct a
>
> if (bridge->driver->agp_destroy_page &&
> bridge->driver->needs_scratch_page) {
> - bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
> - AGP_PAGE_DESTROY_UNMAP);
> - bridge->driver->agp_destroy_page(gart_to_virt(bridge->scratch_page_real),
> - AGP_PAGE_DESTROY_FREE);
> + void *va = gart_to_virt(bridge->scratch_page_real);
> +
> + bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
> + bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
> }
> }
>
> --- a/drivers/char/agp/generic.c
> +++ b/drivers/char/agp/generic.c
> @@ -202,10 +202,13 @@ void agp_free_memory(struct agp_memory *
> }
> if (curr->page_count != 0) {
> for (i = 0; i < curr->page_count; i++) {
> - curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_UNMAP);
> + curr->memory[i] = (unsigned long)gart_to_virt(curr->memory[i]);
> + curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
> + AGP_PAGE_DESTROY_UNMAP);
> }
> for (i = 0; i < curr->page_count; i++) {
> - curr->bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[i]), AGP_PAGE_DESTROY_FREE);
> + curr->bridge->driver->agp_destroy_page((void *)curr->memory[i],
> + AGP_PAGE_DESTROY_FREE);
> }
> }
> agp_free_key(curr->key);
> --- a/drivers/char/agp/intel-agp.c
> +++ b/drivers/char/agp/intel-agp.c
> @@ -428,9 +428,11 @@ static void intel_i810_free_by_type(stru
> if (curr->page_count == 4)
> i8xx_destroy_pages(gart_to_virt(curr->memory[0]));
> else {
> - agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
> + void *va = gart_to_virt(curr->memory[0]);
> +
> + agp_bridge->driver->agp_destroy_page(va,
> AGP_PAGE_DESTROY_UNMAP);
> - agp_bridge->driver->agp_destroy_page(gart_to_virt(curr->memory[0]),
> + agp_bridge->driver->agp_destroy_page(va,
> AGP_PAGE_DESTROY_FREE);
> }
> agp_free_page_array(curr);
>
>
> --
> 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/
>

2008-06-19 09:46:19

by Jan Beulich

[permalink] [raw]
Subject: Re: agp: two-stage page destruction issue

>>> "Dave Airlie" <[email protected]> 19.06.08 01:57 >>>
>On Wed, Jun 18, 2008 at 6:28 PM, Jan Beulich <[email protected]> wrote:
>> Dave,
>>
>> besides it apparently being useful only in 2.6.24 (the changes in 2.6.25
>> really mean that it could be converted back to a single-stage mechanism),
>> I'm seeing an issue in Xen Dom0 kernels, which is caused by the calling
>> of gart_to_virt() in the second stage invocations of the destroy function.
>> I think that besides this being a real issue with Xen (where
>> unmap_page_from_agp() is not just a page table attribute change), this
>> also is invalid from a theoretical perspective: One should not assume that
>> gart_to_virt() is still valid after unmapping a page. So minimally (keeping
>> the 2-stage mechanism) a patch like the one below would be needed.
>>
>
>Looks good to me, its the simpler change for 2.6.26 at this point.
>
>Dave.

So if you're considering it even for 2.6.26, will you push it to Linus? That's
how I understand the process would generally work, or should I push it
in this case (in which case it might be good to know whether your above
statement should be translated into an Acked-by or Signed-off-by)?

Thanks, Jan

2008-06-20 01:47:15

by Dave Airlie

[permalink] [raw]
Subject: Re: agp: two-stage page destruction issue

>
> So if you're considering it even for 2.6.26, will you push it to Linus? That's
> how I understand the process would generally work, or should I push it
> in this case (in which case it might be good to know whether your above
> statement should be translated into an Acked-by or Signed-off-by)?

Its already pushed :)
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=da503fa60b84d5945deb3ab74efdd0bec61df4a1

Dave.