aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/swap.h2
-rw-r--r--kernel/power/swap.c2
-rw-r--r--kernel/power/user.c5
-rw-r--r--mm/swapfile.c38
4 files changed, 31 insertions, 16 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h
index 89f8a39..d51e35e 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -247,7 +247,7 @@ extern int swap_duplicate(swp_entry_t);
extern int valid_swaphandles(swp_entry_t, unsigned long *);
extern void swap_free(swp_entry_t);
extern void free_swap_and_cache(swp_entry_t);
-extern int swap_type_of(dev_t);
+extern int swap_type_of(dev_t, sector_t);
extern unsigned int count_swap_pages(int, int);
extern sector_t map_swap_page(struct swap_info_struct *, pgoff_t);
extern struct swap_info_struct *get_swap_info_struct(unsigned);
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index 1a3b0dd..7b10da1 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -74,7 +74,7 @@ static int mark_swapfiles(swp_entry_t start)
static int swsusp_swap_check(void) /* This is called before saving image */
{
- int res = swap_type_of(swsusp_resume_device);
+ int res = swap_type_of(swsusp_resume_device, 0);
if (res >= 0) {
root_swap = res;
diff --git a/kernel/power/user.c b/kernel/power/user.c
index 4c24ca5..a327b18 100644
--- a/kernel/power/user.c
+++ b/kernel/power/user.c
@@ -55,7 +55,8 @@ static int snapshot_open(struct inode *inode, struct file *filp)
filp->private_data = data;
memset(&data->handle, 0, sizeof(struct snapshot_handle));
if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
- data->swap = swsusp_resume_device ? swap_type_of(swsusp_resume_device) : -1;
+ data->swap = swsusp_resume_device ?
+ swap_type_of(swsusp_resume_device, 0) : -1;
data->mode = O_RDONLY;
} else {
data->swap = -1;
@@ -265,7 +266,7 @@ static int snapshot_ioctl(struct inode *inode, struct file *filp,
* so we need to recode them
*/
if (old_decode_dev(arg)) {
- data->swap = swap_type_of(old_decode_dev(arg));
+ data->swap = swap_type_of(old_decode_dev(arg), 0);
if (data->swap < 0)
error = -ENODEV;
} else {
diff --git a/mm/swapfile.c b/mm/swapfile.c
index f315131..2bfacba 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -427,34 +427,48 @@ void free_swap_and_cache(swp_entry_t entry)
#ifdef CONFIG_SOFTWARE_SUSPEND
/*
- * Find the swap type that corresponds to given device (if any)
+ * 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.
+ * @offset - number of the PAGE_SIZE-sized block of the device, starting
+ * from 0, in which the swap header is expected to be located.
+ *
+ * This is needed for the suspend to disk (aka swsusp).
*/
-int swap_type_of(dev_t device)
+int swap_type_of(dev_t device, sector_t offset)
{
+ struct block_device *bdev = NULL;
int i;
+ if (device)
+ bdev = bdget(device);
+
spin_lock(&swap_lock);
for (i = 0; i < nr_swapfiles; i++) {
- struct inode *inode;
+ struct swap_info_struct *sis = swap_info + i;
- if (!(swap_info[i].flags & SWP_WRITEOK))
+ if (!(sis->flags & SWP_WRITEOK))
continue;
- if (!device) {
+ if (!bdev) {
spin_unlock(&swap_lock);
return i;
}
- inode = swap_info[i].swap_file->f_dentry->d_inode;
- if (S_ISBLK(inode->i_mode) &&
- device == MKDEV(imajor(inode), iminor(inode))) {
- spin_unlock(&swap_lock);
- return i;
+ if (bdev == sis->bdev) {
+ struct swap_extent *se;
+
+ se = list_entry(sis->extent_list.next,
+ struct swap_extent, list);
+ if (se->start_block == offset) {
+ spin_unlock(&swap_lock);
+ bdput(bdev);
+ return i;
+ }
}
}
spin_unlock(&swap_lock);
+ if (bdev)
+ bdput(bdev);
+
return -ENODEV;
}