Re: memcpy() in swsusp (was: Re: [PATCH 2/2] Fix console handling during suspend/resume)

David Brownell
2006-07-06T20:44:42Z

[-- Attachment #1: Type: text/plain, Size: 444 bytes --]

> > Of course it needs fixing ... it's a bug, also a regression.
> >
> > My question is where to fix...
>
> Well, I meant replacing the memcpy() in copy_data_pages with an open coded
> copying loop. That should be enough to fix the problem.

One like this? Yes, it works. The slower speed shouldn't be
much of an issue here. (Though I'm glad that something in RC1
has gotten rid of that slowdown in reading/writing snapshots.)

- Dave

[-- Attachment #2: k7.patch --]
[-- Type: text/x-diff, Size: 1501 bytes --]

On some cpus memcpy() is not appropriate for copying task structs, any more
than copy_page(). For example, on Athlons it uses 3dnow acceleration, which
causes the snapshotted task struct to have the wrong preempt count on resume.

This just replaces the swsusp snapshot memcpy() with an inlined always-safe
version so that hibernation works again on K7 and various other cpus where
such acceleration is used.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/kernel/power/snapshot.c
===================================================================
--- g26.orig/kernel/power/snapshot.c 2006-07-03 10:45:30.000000000 -0700
+++ g26/kernel/power/snapshot.c 2006-07-06 09:33:07.000000000 -0700
@@ -227,11 +227,19 @@ static void copy_data_pages(struct pbe *
for (zone_pfn = 0; zone_pfn < zone->spanned_pages; ++zone_pfn) {
if (saveable(zone, &zone_pfn)) {
struct page *page;
+ u8 *src, *dest, *last;
+
page = pfn_to_page(zone_pfn + zone->zone_start_pfn);
BUG_ON(!pbe);
pbe->orig_address = (unsigned long)page_address(page);
- /* copy_page is not usable for copying task structs. */
- memcpy((void *)pbe->address, (void *)pbe->orig_address, PAGE_SIZE);
+ /* copy_page is not usable for copying task
+ * structs; neither is memcpy on some cpus.
+ */
+ dest = (u8 *)pbe->address;
+ last = dest + PAGE_SIZE;
+ src = (u8 *)pbe->orig_address;
+ while (dest != last)
+ *dest++ = *src++;
pbe = pbe->next;
}
}

[-- Attachment #3: Type: text/plain, Size: 0 bytes --]