diff options
| author | Patrick Mochel <mochel@osdl.org> | 2003-09-21 22:40:25 -0700 |
|---|---|---|
| committer | Patrick Mochel <mochel@osdl.org> | 2003-09-21 22:40:25 -0700 |
| commit | 41d05237ca3ef5b5bdb81f70a90102e65c5a62a2 (patch) | |
| tree | 611f5a6f58739ed712a87010d2d17ea6386c78c0 /kernel | |
| parent | b416e2e21e5f28c46dfd491caafa8810c9a247d6 (diff) | |
[power] pmdisk Cleanups
- Use statically allocated header and info structures.
- Make sure they're packed and page-aligned.
- Make read_swapfiles() return an error if we don't find a valid swap device.
- Store pagedir swap entries in pmdisk_info, eliminating need for linked-list
at the end of each pages. Greatly simplifies code paths for reading/writing.
- Remove several passed-around swap entries.
- Add full utsname struct to pmdisk_info.
- Add some better header checking and debugging information.
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/power/pmdisk.c | 275 |
1 files changed, 127 insertions, 148 deletions
diff --git a/kernel/power/pmdisk.c b/kernel/power/pmdisk.c index 3a86239c9b7c..89ac5f467a0b 100644 --- a/kernel/power/pmdisk.c +++ b/kernel/power/pmdisk.c @@ -76,14 +76,15 @@ struct link { struct pmdisk_info { - u32 version_code; - unsigned long num_physpages; - char machine[8]; - char version[20]; - int cpus; - unsigned long image_pages; - swp_entry_t pagedir_start; -}; + struct new_utsname uts; + u32 version_code; + unsigned long num_physpages; + int cpus; + unsigned long image_pages; + unsigned long pagedir_pages; + swp_entry_t pagedir[768]; +} __attribute__((aligned(PAGE_SIZE))) pmdisk_info; + #define PMDISK_SIG "pmdisk-swap1" @@ -93,7 +94,7 @@ struct pmdisk_header { swp_entry_t pmdisk_info; char orig_sig[10]; char sig[10]; -}; +} __attribute__((packed, aligned(PAGE_SIZE))) pmdisk_header; /* * XXX: We try to keep some more pages free so that I/O operations succeed @@ -115,43 +116,31 @@ struct pmdisk_header { static unsigned short swapfile_used[MAX_SWAPFILES]; static unsigned short root_swap; + static int mark_swapfiles(swp_entry_t prev) { - swp_entry_t entry; - struct pmdisk_header * hdr; int error; - printk( "S" ); - - if (root_swap == 0xFFFF) /* ignored */ - return -EINVAL; - - hdr = (struct pmdisk_header *)get_zeroed_page(GFP_ATOMIC); - if (!hdr) - return -ENOMEM; - - /* XXX: this is dirty hack to get first page of swap file */ - entry = swp_entry(root_swap, 0); - rw_swap_page_sync(READ, entry, virt_to_page((unsigned long)hdr)); - - - if (!memcmp("SWAP-SPACE",hdr->sig,10) || - !memcmp("SWAPSPACE2",hdr->sig,10)) { - memcpy(hdr->orig_sig,hdr->sig,10); - memcpy(hdr->sig,PMDISK_SIG,10); - hdr->pmdisk_info = prev; - - error = rw_swap_page_sync(WRITE, entry, - virt_to_page((unsigned long)hdr)); + rw_swap_page_sync(READ, + swp_entry(root_swap, 0), + virt_to_page((unsigned long)&pmdisk_header)); + if (!memcmp("SWAP-SPACE",pmdisk_header.sig,10) || + !memcmp("SWAPSPACE2",pmdisk_header.sig,10)) { + memcpy(pmdisk_header.orig_sig,pmdisk_header.sig,10); + memcpy(pmdisk_header.sig,PMDISK_SIG,10); + pmdisk_header.pmdisk_info = prev; + error = rw_swap_page_sync(WRITE, + swp_entry(root_swap, 0), + virt_to_page((unsigned long) + &pmdisk_header)); } else { pr_debug("pmdisk: Partition is not swap space.\n"); error = -ENODEV; } - free_page((unsigned long)hdr); return error; } -static void read_swapfiles(void) /* This is called before saving image */ +static int read_swapfiles(void) /* This is called before saving image */ { int i, len; @@ -182,6 +171,7 @@ static void read_swapfiles(void) /* This is called before saving image */ } } swap_list_unlock(); + return (root_swap != 0xffff) ? 0 : -ENODEV; } @@ -275,7 +265,7 @@ static int write_data(void) error = write_swap_page((pm_pagedir_nosave+i)->address, &((pm_pagedir_nosave+i)->swap_address)); } - printk( "|\n" ); + printk(" %d Pages done.\n",i); return error; } @@ -286,17 +276,11 @@ static int write_data(void) static void free_pagedir_entries(void) { - int num = SUSPEND_PD_PAGES(pmdisk_pages); - struct link * link; - swp_entry_t entry; + int num = pmdisk_info.pagedir_pages; int i; - for (i = 0; i < num; i++) { - link = (struct link *)((char *) pm_pagedir_nosave)+i; - entry = link->next; - if (entry.val) - swap_free(entry); - } + for (i = 0; i < num; i++) + swap_free(pmdisk_info.pagedir[i]); } @@ -305,26 +289,54 @@ static void free_pagedir_entries(void) * @last: Last swap entry we write (needed for header). */ -static int write_pagedir(swp_entry_t * last) +static int write_pagedir(void) { - int nr_pgdir_pages = SUSPEND_PD_PAGES(pmdisk_pages); - struct link * link; - swp_entry_t prev = {0}; + unsigned long addr = (unsigned long)pm_pagedir_nosave; int error = 0; + int n = SUSPEND_PD_PAGES(pmdisk_pages); int i; - printk( "Writing pagedir (%d pages): ", nr_pgdir_pages); - for (i = 0; i < nr_pgdir_pages && !error; i++) { - link = (struct link *)((char *) pm_pagedir_nosave + i * PAGE_SIZE); - printk( "." ); - link->next = prev; - error = write_swap_page((unsigned long)link,&prev); - } - *last = prev; + pmdisk_info.pagedir_pages = n; + printk( "Writing pagedir (%d pages)\n", n); + for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) + error = write_swap_page(addr,&pmdisk_info.pagedir[i]); return error; } +#ifdef DEBUG +static void dump_pmdisk_info(void) +{ + printk(" pmdisk: Version: %u\n",pmdisk_info.version_code); + printk(" pmdisk: Num Pages: %ld\n",pmdisk_info.num_physpages); + printk(" pmdisk: UTS Sys: %s\n",pmdisk_info.uts.sysname); + printk(" pmdisk: UTS Node: %s\n",pmdisk_info.uts.nodename); + printk(" pmdisk: UTS Release: %s\n",pmdisk_info.uts.release); + printk(" pmdisk: UTS Version: %s\n",pmdisk_info.uts.version); + printk(" pmdisk: UTS Machine: %s\n",pmdisk_info.uts.machine); + printk(" pmdisk: UTS Domain: %s\n",pmdisk_info.uts.domainname); + printk(" pmdisk: CPUs: %d\n",pmdisk_info.cpus); + printk(" pmdisk: Image: %ld Pages\n",pmdisk_info.image_pages); + printk(" pmdisk: Pagedir: %ld Pages\n",pmdisk_info.pagedir_pages); +} +#else +static void dump_pmdisk_info(void) +{ + +} +#endif + +static void init_header(void) +{ + memset(&pmdisk_info,0,sizeof(pmdisk_info)); + pmdisk_info.version_code = LINUX_VERSION_CODE; + pmdisk_info.num_physpages = num_physpages; + memcpy(&pmdisk_info.uts,&system_utsname,sizeof(system_utsname)); + + pmdisk_info.cpus = num_online_cpus(); + pmdisk_info.image_pages = pmdisk_pages; +} + /** * write_header - Fill and write the suspend header. * @entry: Location of the last swap entry used. @@ -337,27 +349,12 @@ static int write_pagedir(swp_entry_t * last) static int write_header(swp_entry_t * entry) { - struct pmdisk_info * hdr; - int error; - - hdr = (struct pmdisk_info *)get_zeroed_page(GFP_ATOMIC); - if (!hdr) - return -ENOMEM; - - hdr->version_code = LINUX_VERSION_CODE; - hdr->num_physpages = num_physpages; - strncpy(hdr->machine, system_utsname.machine, 8); - strncpy(hdr->version, system_utsname.version, 20); - - hdr->cpus = num_online_cpus(); - hdr->image_pages = pmdisk_pages; - hdr->pagedir_start = *entry; - error = write_swap_page((unsigned long)hdr,entry); - free_page((unsigned long)hdr); - return error; + dump_pmdisk_info(); + return write_swap_page((unsigned long)&pmdisk_info,entry); } + /** * write_suspend_image - Write entire image and metadata. * @@ -368,17 +365,18 @@ static int write_suspend_image(void) int error; swp_entry_t prev = { 0 }; + init_header(); + if ((error = write_data())) goto FreeData; - if ((error = write_pagedir(&prev))) + if ((error = write_pagedir())) goto FreePagedir; if ((error = write_header(&prev))) goto FreePagedir; error = mark_swapfiles(prev); - printk( "|\n" ); Done: return error; FreePagedir: @@ -631,7 +629,9 @@ int pmdisk_suspend(void) { int error = 0; - read_swapfiles(); + if ((error = read_swapfiles())) + return error; + drain_local_pages(); pm_pagedir_nosave = NULL; @@ -925,38 +925,26 @@ write_page(pgoff_t page_off, void * page) extern dev_t __init name_to_dev_t(const char *line); -#define next_entry(link) (link)->next - - -static int __init check_sig(swp_entry_t * next) +static int __init check_sig(void) { - struct pmdisk_header * hdr; int error; - hdr = (struct pmdisk_header *)get_zeroed_page(GFP_ATOMIC); - if (!hdr) - return -ENOMEM; - - if ((error = read_page(0,hdr))) - goto Done; - - if (!memcmp(PMDISK_SIG,hdr->sig,10)) { - memcpy(hdr->sig,hdr->orig_sig,10); - *next = hdr->pmdisk_info; + memset(&pmdisk_header,0,sizeof(pmdisk_header)); + if ((error = read_page(0,&pmdisk_header))) + return error; + if (!memcmp(PMDISK_SIG,pmdisk_header.sig,10)) { + memcpy(pmdisk_header.sig,pmdisk_header.orig_sig,10); /* * Reset swap signature now. */ - error = write_page(0,hdr); + error = write_page(0,&pmdisk_header); } else { pr_debug(KERN_ERR "pmdisk: Invalid partition type.\n"); - error = -EINVAL; + return -EINVAL; } - if (!error) pr_debug("pmdisk: Signature found, resuming\n"); - Done: - free_page((unsigned long)hdr); return error; } @@ -966,78 +954,70 @@ static int __init check_sig(swp_entry_t * next) * I really don't think that it's foolproof but more than nothing.. */ -static const char * __init sanity_check(struct pmdisk_info * hdr) +static const char * __init sanity_check(void) { - if(hdr->version_code != LINUX_VERSION_CODE) - return "Incorrect kernel version"; - if(hdr->num_physpages != num_physpages) - return "Incorrect memory size"; - if(strncmp(hdr->machine, system_utsname.machine, 8)) - return "Incorrect machine type"; - if(strncmp(hdr->version, system_utsname.version, 20)) - return "Incorrect version"; - if(hdr->cpus != num_online_cpus()) - return "Incorrect number of cpus"; + dump_pmdisk_info(); + if(pmdisk_info.version_code != LINUX_VERSION_CODE) + return "kernel version"; + if(pmdisk_info.num_physpages != num_physpages) + return "memory size"; + if (strcmp(pmdisk_info.uts.sysname,system_utsname.sysname)) + return "system type"; + if (strcmp(pmdisk_info.uts.release,system_utsname.release)) + return "kernel release"; + if (strcmp(pmdisk_info.uts.version,system_utsname.version)) + return "version"; + if (strcmp(pmdisk_info.uts.machine,system_utsname.machine)) + return "machine"; + if(pmdisk_info.cpus != num_online_cpus()) + return "number of cpus"; return 0; } -static int __init check_header(swp_entry_t * next) +static int __init check_header(void) { - struct pmdisk_info * hdr; const char * reason = NULL; int error; - hdr = (struct pmdisk_info *)get_zeroed_page(GFP_ATOMIC); - if (!hdr) - return -ENOMEM; + init_header(); - if ((error = read_page(swp_offset(*next), hdr))) - goto Done; + if ((error = read_page(swp_offset(pmdisk_header.pmdisk_info), + &pmdisk_info))) + return error; /* Is this same machine? */ - if ((reason = sanity_check(hdr))) { + if ((reason = sanity_check())) { printk(KERN_ERR "pmdisk: Resume mismatch: %s\n",reason); - error = -EPERM; - goto Done; + return -EPERM; } - - *next = hdr->pagedir_start; - pmdisk_pages = hdr->image_pages; - Done: - free_page((unsigned long)hdr); + pmdisk_pages = pmdisk_info.image_pages; return error; } -static int __init read_pagedir(swp_entry_t start) +static int __init read_pagedir(void) { - int i, nr_pgdir_pages; - swp_entry_t entry = start; + unsigned long addr; + int i, n = pmdisk_info.pagedir_pages; int error = 0; - nr_pgdir_pages = SUSPEND_PD_PAGES(pmdisk_pages); - pagedir_order = get_bitmask_order(nr_pgdir_pages); + pagedir_order = get_bitmask_order(n); - pm_pagedir_nosave = (suspend_pagedir_t *)__get_free_pages(GFP_ATOMIC, pagedir_order); - if (!pm_pagedir_nosave) + addr =__get_free_pages(GFP_ATOMIC, pagedir_order); + if (!addr) return -ENOMEM; + pm_pagedir_nosave = (struct pbe *)addr; - pr_debug("pmdisk: sReading pagedir\n"); + pr_debug("pmdisk: Reading pagedir (%d Pages)\n",n); - /* We get pages in reverse order of saving! */ - for (i = nr_pgdir_pages-1; i >= 0 && !error; i--) { - void * data = ((char *)pm_pagedir_nosave) + i * PAGE_SIZE; - unsigned long offset = swp_offset(entry); - - if (offset) { - if (!(error = read_page(offset, data))) - entry = next_entry((struct link *)data); - } else + for (i = 0; i < n && !error; i++, addr += PAGE_SIZE) { + unsigned long offset = swp_offset(pmdisk_info.pagedir[i]); + if (offset) + error = read_page(offset, (void *)addr); + else error = -EFAULT; } - if (swp_offset(entry)) - error = -E2BIG; if (error) free_pages((unsigned long)pm_pagedir_nosave,pagedir_order); return error; @@ -1064,21 +1044,20 @@ static int __init read_image_data(void) error = read_page(swp_offset(p->swap_address), (void *)p->address); } - printk(" %d done|\n",i); + printk(" %d done.\n",i); return error; } static int __init read_suspend_image(void) { - swp_entry_t next; int error = 0; - if ((error = check_sig(&next))) + if ((error = check_sig())) return error; - if ((error = check_header(&next))) + if ((error = check_header())) return error; - if ((error = read_pagedir(next))) + if ((error = read_pagedir())) return error; if ((error = relocate_pagedir())) goto FreePagedir; |
