Commit f577eb30 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki Committed by Linus Torvalds

[PATCH] swsusp: low level interface

Introduce the low level interface that can be used for handling the
snapshot of the system memory by the in-kernel swap-writing/reading code of
swsusp and the userland interface code (to be introduced shortly).

Also change the way in which swsusp records the allocated swap pages and,
consequently, simplifies the in-kernel swap-writing/reading code (this is
necessary for the userland interface too).  To this end, it introduces two
helper functions in mm/swapfile.c, so that the swsusp code does not refer
directly to the swap internals.
Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarPavel Machek <pavel@ucw.cz>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 2b322ce2
...@@ -234,14 +234,15 @@ extern struct page * read_swap_cache_async(swp_entry_t, struct vm_area_struct *v ...@@ -234,14 +234,15 @@ extern struct page * read_swap_cache_async(swp_entry_t, struct vm_area_struct *v
/* linux/mm/swapfile.c */ /* linux/mm/swapfile.c */
extern long total_swap_pages; extern long total_swap_pages;
extern unsigned int nr_swapfiles; extern unsigned int nr_swapfiles;
extern struct swap_info_struct swap_info[];
extern void si_swapinfo(struct sysinfo *); extern void si_swapinfo(struct sysinfo *);
extern swp_entry_t get_swap_page(void); extern swp_entry_t get_swap_page(void);
extern swp_entry_t get_swap_page_of_type(int type); extern swp_entry_t get_swap_page_of_type(int);
extern int swap_duplicate(swp_entry_t); extern int swap_duplicate(swp_entry_t);
extern int valid_swaphandles(swp_entry_t, unsigned long *); extern int valid_swaphandles(swp_entry_t, unsigned long *);
extern void swap_free(swp_entry_t); extern void swap_free(swp_entry_t);
extern void free_swap_and_cache(swp_entry_t); extern void free_swap_and_cache(swp_entry_t);
extern int swap_type_of(dev_t);
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t); extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t);
extern struct swap_info_struct *get_swap_info_struct(unsigned); extern struct swap_info_struct *get_swap_info_struct(unsigned);
extern int can_share_swap_page(struct page *); extern int can_share_swap_page(struct page *);
......
...@@ -26,9 +26,9 @@ extern suspend_disk_method_t pm_disk_mode; ...@@ -26,9 +26,9 @@ extern suspend_disk_method_t pm_disk_mode;
extern int swsusp_shrink_memory(void); extern int swsusp_shrink_memory(void);
extern int swsusp_suspend(void); extern int swsusp_suspend(void);
extern int swsusp_write(struct pbe *pblist, unsigned int nr_pages); extern int swsusp_write(void);
extern int swsusp_check(void); extern int swsusp_check(void);
extern int swsusp_read(struct pbe **pblist_ptr); extern int swsusp_read(void);
extern void swsusp_close(void); extern void swsusp_close(void);
extern int swsusp_resume(void); extern int swsusp_resume(void);
...@@ -70,10 +70,6 @@ static void power_down(suspend_disk_method_t mode) ...@@ -70,10 +70,6 @@ static void power_down(suspend_disk_method_t mode)
while(1); while(1);
} }
static int in_suspend __nosavedata = 0;
static inline void platform_finish(void) static inline void platform_finish(void)
{ {
if (pm_disk_mode == PM_DISK_PLATFORM) { if (pm_disk_mode == PM_DISK_PLATFORM) {
...@@ -145,7 +141,7 @@ int pm_suspend_disk(void) ...@@ -145,7 +141,7 @@ int pm_suspend_disk(void)
if (in_suspend) { if (in_suspend) {
device_resume(); device_resume();
pr_debug("PM: writing image.\n"); pr_debug("PM: writing image.\n");
error = swsusp_write(pagedir_nosave, nr_copy_pages); error = swsusp_write();
if (!error) if (!error)
power_down(pm_disk_mode); power_down(pm_disk_mode);
else { else {
...@@ -216,7 +212,7 @@ static int software_resume(void) ...@@ -216,7 +212,7 @@ static int software_resume(void)
pr_debug("PM: Reading swsusp image.\n"); pr_debug("PM: Reading swsusp image.\n");
if ((error = swsusp_read(&pagedir_nosave))) { if ((error = swsusp_read())) {
swsusp_free(); swsusp_free();
goto Thaw; goto Thaw;
} }
......
...@@ -37,21 +37,31 @@ extern struct subsystem power_subsys; ...@@ -37,21 +37,31 @@ extern struct subsystem power_subsys;
/* References to section boundaries */ /* References to section boundaries */
extern const void __nosave_begin, __nosave_end; extern const void __nosave_begin, __nosave_end;
extern unsigned int nr_copy_pages;
extern struct pbe *pagedir_nosave; extern struct pbe *pagedir_nosave;
/* Preferred image size in bytes (default 500 MB) */ /* Preferred image size in bytes (default 500 MB) */
extern unsigned long image_size; extern unsigned long image_size;
extern int in_suspend;
extern asmlinkage int swsusp_arch_suspend(void); extern asmlinkage int swsusp_arch_suspend(void);
extern asmlinkage int swsusp_arch_resume(void); extern asmlinkage int swsusp_arch_resume(void);
extern unsigned int count_data_pages(void); extern unsigned int count_data_pages(void);
extern void free_pagedir(struct pbe *pblist);
extern void release_eaten_pages(void);
extern struct pbe *alloc_pagedir(unsigned nr_pages, gfp_t gfp_mask, int safe_needed);
extern void swsusp_free(void); extern void swsusp_free(void);
extern int alloc_data_pages(struct pbe *pblist, gfp_t gfp_mask, int safe_needed);
extern unsigned int snapshot_nr_pages(void); struct snapshot_handle {
extern struct pbe *snapshot_pblist(void); loff_t offset;
extern void snapshot_pblist_set(struct pbe *pblist); unsigned int page;
unsigned int page_offset;
unsigned int prev;
struct pbe *pbe;
void *buffer;
unsigned int buf_offset;
};
#define data_of(handle) ((handle).buffer + (handle).buf_offset)
extern int snapshot_read_next(struct snapshot_handle *handle, size_t count);
extern int snapshot_write_next(struct snapshot_handle *handle, size_t count);
int snapshot_image_loaded(struct snapshot_handle *handle);
This diff is collapsed.
This diff is collapsed.
...@@ -45,7 +45,7 @@ static const char Unused_offset[] = "Unused swap offset entry "; ...@@ -45,7 +45,7 @@ static const char Unused_offset[] = "Unused swap offset entry ";
struct swap_list_t swap_list = {-1, -1}; struct swap_list_t swap_list = {-1, -1};
struct swap_info_struct swap_info[MAX_SWAPFILES]; static struct swap_info_struct swap_info[MAX_SWAPFILES];
static DEFINE_MUTEX(swapon_mutex); static DEFINE_MUTEX(swapon_mutex);
...@@ -417,6 +417,59 @@ void free_swap_and_cache(swp_entry_t entry) ...@@ -417,6 +417,59 @@ void free_swap_and_cache(swp_entry_t entry)
} }
} }
#ifdef CONFIG_SOFTWARE_SUSPEND
/*
* Find the swap type that corresponds to given device (if any)
*
* This is needed for software suspend and is done in such a way that inode
* aliasing is allowed.
*/
int swap_type_of(dev_t device)
{
int i;
if (!device)
return -EINVAL;
spin_lock(&swap_lock);
for (i = 0; i < nr_swapfiles; i++) {
struct inode *inode;
if (!(swap_info[i].flags & SWP_WRITEOK))
continue;
inode = swap_info->swap_file->f_dentry->d_inode;
if (S_ISBLK(inode->i_mode) &&
device == MKDEV(imajor(inode), iminor(inode))) {
spin_unlock(&swap_lock);
return i;
}
}
spin_unlock(&swap_lock);
return -ENODEV;
}
/*
* Return either the total number of swap pages of given type, or the number
* of free pages of that type (depending on @free)
*
* This is needed for software suspend
*/
unsigned int count_swap_pages(int type, int free)
{
unsigned int n = 0;
if (type < nr_swapfiles) {
spin_lock(&swap_lock);
if (swap_info[type].flags & SWP_WRITEOK) {
n = swap_info[type].pages;
if (free)
n -= swap_info[type].inuse_pages;
}
spin_unlock(&swap_lock);
}
return n;
}
#endif
/* /*
* No need to decide whether this PTE shares the swap entry with others, * No need to decide whether this PTE shares the swap entry with others,
* just let do_wp_page work it out if a write is requested later - to * just let do_wp_page work it out if a write is requested later - to
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment