diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2011-07-09 01:30:40 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2011-07-09 01:30:40 +0000 |
commit | fcb72f95947e42c2d4ae9d7baa5d0fca11be731e (patch) | |
tree | 9d2cd0300c27c22571aa67bf913639c06a927c6d | |
parent | b62ede43b6ac09cc9ba3315db12e28c440c2cce1 (diff) |
Extract hibernate_write_signature and hibernate_clear_signature to the MI
hibernate code, and add chunk range overlap checking.
-rw-r--r-- | sys/arch/i386/i386/hibernate_machdep.c | 50 | ||||
-rw-r--r-- | sys/kern/subr_hibernate.c | 124 | ||||
-rw-r--r-- | sys/sys/hibernate.h | 7 |
3 files changed, 130 insertions, 51 deletions
diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index 61f3809829d..cb7f194b1b6 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -54,9 +54,6 @@ void hibernate_enter_resume_4k_pde(vaddr_t); void hibernate_enter_resume_4m_pde(vaddr_t, paddr_t); void hibernate_populate_resume_pt(paddr_t *, paddr_t *); int get_hibernate_info_md(union hibernate_info *); -int hibernate_write_signature(void); -int hibernate_clear_signature(void); -int hibernate_inflate_skip(paddr_t); union hibernate_info *global_hiber_info; paddr_t global_image_start; @@ -324,7 +321,7 @@ hibernate_write_image() } /* Image write complete, write the signature and return */ - return hibernate_write_signature(); + return hibernate_write_signature(&hiber_info); } int @@ -489,51 +486,6 @@ hibernate_resume() hibernate_resume_machine(); } -int -hibernate_write_signature() -{ - union hibernate_info hiber_info; - u_int8_t *io_page; - - /* Get current running machine's hibernate info */ - if (get_hibernate_info(&hiber_info)) - return (1); - - io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (!io_page) - return (1); - - /* Write hibernate info to disk */ - hiber_info.io_func(hiber_info.device, hiber_info.sig_offset, - (vaddr_t)&hiber_info, 512, 1, io_page); - - free(io_page, M_DEVBUF); - - return (0); -} - -int -hibernate_clear_signature() -{ - union hibernate_info hiber_info; - u_int8_t *io_page; - - /* Zero out a blank hiber_info */ - bzero(&hiber_info, sizeof(hiber_info)); - - io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); - if (!io_page) - return (1); - - /* Write (zeroed) hibernate info to disk */ - hiber_info.io_func(hiber_info.device, hiber_info.sig_offset, - (vaddr_t)&hiber_info, 512, 1, io_page); - - free(io_page, M_DEVBUF); - - return (0); -} - /* * hibernate_inflate_skip * diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index bbb7a9f7de3..69cfb2f25ca 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.10 2011/07/09 00:55:00 mlarkin Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.11 2011/07/09 01:30:39 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -17,6 +17,7 @@ */ #include <sys/hibernate.h> +#include <sys/malloc.h> #include <sys/param.h> #include <sys/tree.h> #include <sys/types.h> @@ -610,6 +611,19 @@ void } /* + * hibernate_zlib_free + * + * Free the memory pointed to by addr in the hiballoc area presently in + * use + * + */ +void +hibernate_zlib_free(void *unused, void *addr) +{ + hib_free(&hibernate_state->hiballoc_arena, addr); +} + +/* * hibernate_inflate * * Inflate size bytes from src into dest, skipping any pages in @@ -697,3 +711,111 @@ hibernate_deflate(paddr_t src, size_t *remaining) return (PAGE_SIZE - (src & PAGE_MASK)) - hibernate_state->hib_stream.avail_in; } + +/* + * hibernate_write_signature + * + * Write the hibernation information specified in hiber_info + * to the location in swap previously calculated (last block of + * swap), called the "signature block". + * + * Write the memory chunk table to the area in swap immediately + * preceding the signature block. + */ +int +hibernate_write_signature(union hibernate_info *hiber_info) +{ + u_int8_t *io_page; + daddr_t chunkbase; + size_t i; + + io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + if (!io_page) + return (1); + + /* Write hibernate info to disk */ + if( hiber_info->io_func(hiber_info->device, hiber_info->sig_offset, + (vaddr_t)hiber_info, hiber_info->secsize, 1, io_page)) + panic("error in hibernate write sig\n"); + + chunkbase = hiber_info->sig_offset - + (HIBERNATE_CHUNK_TABLE_SIZE / hiber_info->secsize); + + /* Write chunk table */ + for(i=0; i < HIBERNATE_CHUNK_TABLE_SIZE; i += NBPG) { + if(hiber_info->io_func(hiber_info->device, + chunkbase + (i/hiber_info->secsize), + (vaddr_t)(HIBERNATE_CHUNK_TABLE_START + i), + NBPG, + 1, + io_page)) + panic("error in hibernate write chunks\n"); + } + + free(io_page, M_DEVBUF); + + return (0); +} + +/* + * hibernate_clear_signature + * + * Write an empty hiber_info to the swap signature block, which is + * guaranteed to not match any valid hiber_info. + */ +int +hibernate_clear_signature() +{ + union hibernate_info blank_hiber_info; + union hibernate_info hiber_info; + u_int8_t *io_page; + + /* Zero out a blank hiber_info */ + bzero(&blank_hiber_info, sizeof(hiber_info)); + + if (get_hibernate_info(&hiber_info)) + return (1); + + io_page = malloc(PAGE_SIZE, M_DEVBUF, M_NOWAIT); + if (!io_page) + return (1); + + /* Write (zeroed) hibernate info to disk */ + if(hiber_info.io_func(hiber_info.device, hiber_info.sig_offset, + (vaddr_t)&blank_hiber_info, hiber_info.secsize, 1, io_page)) + panic("error hibernate write 6\n"); + + free(io_page, M_DEVBUF); + + return (0); +} + +/* + * hibernate_check_overlap + * + * Check chunk range overlap when calculating whether or not to copy a + * compressed chunk to the piglet area before decompressing. + * + * returns zero if the ranges do not overlap, non-zero otherwise. + */ +int +hibernate_check_overlap(paddr_t r1s, paddr_t r1e, paddr_t r2s, paddr_t r2e) +{ + /* case A : end of r1 overlaps start of r2 */ + if (r1s < r2s && r1e > r2s) + return (1); + + /* case B : r1 entirely inside r2 */ + if (r1s >= r2s && r1e <= r2e) + return (1); + + /* case C : r2 entirely inside r1 */ + if (r2s >= r1s && r2e <= r1e) + return (1); + + /* case D : end of r2 overlaps start of r1 */ + if (r2s < r1s && r2e > r1s) + return (1); + + return (0); +} diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h index 58b28f15550..5e3bfbfe4ef 100644 --- a/sys/sys/hibernate.h +++ b/sys/sys/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.9 2011/07/09 00:55:00 mlarkin Exp $ */ +/* $OpenBSD: hibernate.h,v 1.10 2011/07/09 01:30:39 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -119,4 +119,9 @@ void hibernate_zlib_free(void *, void *); void hibernate_inflate(paddr_t, paddr_t, size_t); size_t hibernate_deflate(paddr_t, size_t *); +int hibernate_write_signature(union hibernate_info *); +int hibernate_clear_signature(void); + +int hibernate_check_overlap(paddr_t, paddr_t, paddr_t, paddr_t); + #endif /* _SYS_HIBERNATE_H_ */ |