2009-01-27 22:20:04

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 0/1] PM/Hibernate: fix "swap breaks after hibernation failures"

Hi Len,

The following patch fixes a long-standing bug in the hibernate code related to
swap, which causes the swap partition used for saving hibernation images to
become unusable after two consecutive failing attempts to hibernate.

Please add to the suspend branch as 2.6.29 material.

Thanks,
Rafael


2009-01-27 22:20:33

by Rafael J. Wysocki

[permalink] [raw]
Subject: [PATCH 1/1] PM/Hibernate: fix "swap breaks after hibernation failures"

From: Alan Jenkins <[email protected]>

http://bugzilla.kernel.org/show_bug.cgi?id=12239

The image writing code dropped a reference to the current swap device.
This doesn't show up if the hibernation succeeds - because it doesn't
affect the image which gets resumed. But it means multiple _failed_
hibernations end up freeing the swap device while it is still use!

swsusp_write() finds the block device for the swap file using swap_type_of().
It then uses blkdev_get() / blkdev_put() to open and close the block device.

Unfortunately, blkdev_get() assumes ownership of the inode of the block_device
passed to it. So blkdev_put() calls iput() on the inode. This is by design
and other callers expect this behaviour. The fix is for swap_type_of() to take
a reference on the inode using bdget().

Signed-off-by: Alan Jenkins <[email protected]>
Signed-off-by: Rafael J. Wysocki <[email protected]>

diff --git a/mm/swapfile.c b/mm/swapfile.c
index f48b831..7740478 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)

if (!bdev) {
if (bdev_p)
- *bdev_p = sis->bdev;
+ *bdev_p = bdget(sis->bdev->bd_dev);

spin_unlock(&swap_lock);
return i;
@@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
struct swap_extent, list);
if (se->start_block == offset) {
if (bdev_p)
- *bdev_p = sis->bdev;
+ *bdev_p = bdget(sis->bdev->bd_dev);

spin_unlock(&swap_lock);
bdput(bdev);



2009-01-28 09:27:31

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH 1/1] PM/Hibernate: fix "swap breaks after hibernation failures"

On Tue 2009-01-27 23:18:59, Rafael J. Wysocki wrote:
> From: Alan Jenkins <[email protected]>
>
> http://bugzilla.kernel.org/show_bug.cgi?id=12239
>
> The image writing code dropped a reference to the current swap device.
> This doesn't show up if the hibernation succeeds - because it doesn't
> affect the image which gets resumed. But it means multiple _failed_
> hibernations end up freeing the swap device while it is still use!
>
> swsusp_write() finds the block device for the swap file using swap_type_of().
> It then uses blkdev_get() / blkdev_put() to open and close the block device.
>
> Unfortunately, blkdev_get() assumes ownership of the inode of the block_device
> passed to it. So blkdev_put() calls iput() on the inode. This is by design
> and other callers expect this behaviour. The fix is for swap_type_of() to take
> a reference on the inode using bdget().
>
> Signed-off-by: Alan Jenkins <[email protected]>
> Signed-off-by: Rafael J. Wysocki <[email protected]>

Acked-by: Pavel Machek <[email protected]>

>
> diff --git a/mm/swapfile.c b/mm/swapfile.c
> index f48b831..7740478 100644
> --- a/mm/swapfile.c
> +++ b/mm/swapfile.c
> @@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
>
> if (!bdev) {
> if (bdev_p)
> - *bdev_p = sis->bdev;
> + *bdev_p = bdget(sis->bdev->bd_dev);
>
> spin_unlock(&swap_lock);
> return i;
> @@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
> struct swap_extent, list);
> if (se->start_block == offset) {
> if (bdev_p)
> - *bdev_p = sis->bdev;
> + *bdev_p = bdget(sis->bdev->bd_dev);
>
> spin_unlock(&swap_lock);
> bdput(bdev);
>
>
>
>

--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html