Commit 1d819b9d authored by Pavel Machek's avatar Pavel Machek Committed by Jaroslav Kysela

[PATCH] Swsusp updates, do not thrash ide disk on suspend

This cleans up swsusp a little bit and fixes ide disk corruption on
suspend/resume.
									Pavel
parent 05684a49
...@@ -156,6 +156,23 @@ Drivers that need support ...@@ -156,6 +156,23 @@ Drivers that need support
- do IDE cdroms need some kind of support? - do IDE cdroms need some kind of support?
- IDE CD-RW -- how to deal with that? - IDE CD-RW -- how to deal with that?
FAQ:
Q: well, suspending a server is IMHO a really stupid thing,
but... (Diego Zuccato):
A: You bought new UPS for your server. How do you install it without
bringing machine down? Suspend to disk, rearrange power cables,
resume.
You have your server on UPS. Power died, and UPS is indicating 30
seconds to failure. What do you do? Suspend to disk.
Ethernet card in your server died. You want to replace it. Your
server is not hotplug capable. What do you do? Suspend to disk,
replace ethernet card, resume. If you are fast your users will not
even see broken connections.
Any other idea you might have tell me! Any other idea you might have tell me!
Contacting the author Contacting the author
......
...@@ -544,6 +544,7 @@ static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned ...@@ -544,6 +544,7 @@ static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned
*/ */
static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) static ide_startstop_t do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{ {
BUG_ON(drive->blocked);
if (!blk_fs_request(rq)) { if (!blk_fs_request(rq)) {
blk_dump_rq_flags(rq, "do_rw_disk - bad command"); blk_dump_rq_flags(rq, "do_rw_disk - bad command");
ide_end_request(drive, 0, 0); ide_end_request(drive, 0, 0);
...@@ -1495,6 +1496,68 @@ static void idedisk_add_settings(ide_drive_t *drive) ...@@ -1495,6 +1496,68 @@ static void idedisk_add_settings(ide_drive_t *drive)
ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL); ide_add_setting(drive, "max_failures", SETTING_RW, -1, -1, TYPE_INT, 0, 65535, 1, 1, &drive->max_failures, NULL);
} }
static int idedisk_suspend(struct device *dev, u32 state, u32 level)
{
ide_drive_t *drive = dev->driver_data;
printk("Suspending device %lx\n", dev->driver_data);
/* I hope that every freeze operation from the upper levels have
* already been done...
*/
if (level != SUSPEND_SAVE_STATE)
return 0;
BUG_ON(in_interrupt());
printk("Waiting for commands to finish\n");
/* wait until all commands are finished */
/* FIXME: waiting for spinlocks should be done instead. */
if (!(HWGROUP(drive)))
printk("No hwgroup?\n");
while (HWGROUP(drive)->handler)
yield();
/* set the drive to standby */
printk(KERN_INFO "suspending: %s ", drive->name);
if (drive->driver) {
if (drive->driver->standby)
drive->driver->standby(drive);
}
drive->blocked = 1;
while (HWGROUP(drive)->handler)
yield();
return 0;
}
static int idedisk_resume(struct device *dev, u32 level)
{
ide_drive_t *drive = dev->driver_data;
if (level != RESUME_RESTORE_STATE)
return 0;
if (!drive->blocked)
panic("ide: Resume but not suspended?\n");
drive->blocked = 0;
return 0;
}
/* This is just a hook for the overall driver tree.
*/
static struct device_driver idedisk_devdrv = {
.bus = &ide_bus_type,
.name = "IDE disk driver",
.suspend = idedisk_suspend,
.resume = idedisk_resume,
};
static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode, static int idedisk_ioctl (ide_drive_t *drive, struct inode *inode,
struct file *file, unsigned int cmd, unsigned long arg) struct file *file, unsigned int cmd, unsigned long arg)
{ {
...@@ -1540,6 +1603,11 @@ static void idedisk_setup (ide_drive_t *drive) ...@@ -1540,6 +1603,11 @@ static void idedisk_setup (ide_drive_t *drive)
drive->doorlocking = 1; drive->doorlocking = 1;
} }
} }
{
sprintf(drive->disk->disk_dev.name, "ide-disk");
drive->disk->disk_dev.driver = &idedisk_devdrv;
drive->disk->disk_dev.driver_data = drive;
}
#if 1 #if 1
(void) probe_lba_addressing(drive, 1); (void) probe_lba_addressing(drive, 1);
...@@ -1623,6 +1691,8 @@ static void idedisk_setup (ide_drive_t *drive) ...@@ -1623,6 +1691,8 @@ static void idedisk_setup (ide_drive_t *drive)
static int idedisk_cleanup (ide_drive_t *drive) static int idedisk_cleanup (ide_drive_t *drive)
{ {
struct gendisk *g = drive->disk; struct gendisk *g = drive->disk;
put_device(&drive->disk->disk_dev);
if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache) if ((drive->id->cfs_enable_2 & 0x3000) && drive->wcache)
if (do_idedisk_flushcache(drive)) if (do_idedisk_flushcache(drive))
printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n", printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",
...@@ -1721,6 +1791,7 @@ static void __exit idedisk_exit (void) ...@@ -1721,6 +1791,7 @@ static void __exit idedisk_exit (void)
static int idedisk_init (void) static int idedisk_init (void)
{ {
ide_register_driver(&idedisk_driver); ide_register_driver(&idedisk_driver);
driver_register(&idedisk_devdrv);
return 0; return 0;
} }
......
...@@ -52,6 +52,7 @@ struct pnp_dev_t { ...@@ -52,6 +52,7 @@ struct pnp_dev_t {
static int __init pnpide_generic_init(struct pci_dev *dev, int enable) static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
{ {
hw_regs_t hw; hw_regs_t hw;
ide_hwif_t *hwif;
int index; int index;
if (!enable) if (!enable)
...@@ -67,10 +68,11 @@ static int __init pnpide_generic_init(struct pci_dev *dev, int enable) ...@@ -67,10 +68,11 @@ static int __init pnpide_generic_init(struct pci_dev *dev, int enable)
// generic_pnp_ide_iops, // generic_pnp_ide_iops,
DEV_IRQ(dev, 0)); DEV_IRQ(dev, 0));
index = ide_register_hw(&hw, NULL); index = ide_register_hw(&hw, &hwif);
if (index != -1) { if (index != -1) {
printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev)); printk(KERN_INFO "ide%d: %s IDE interface\n", index, DEV_NAME(dev));
hwif->pci_dev = dev;
return 0; return 0;
} }
......
...@@ -46,6 +46,7 @@ ...@@ -46,6 +46,7 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/ide.h> #include <linux/ide.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/pci.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -566,6 +567,11 @@ static void hwif_register (ide_hwif_t *hwif) ...@@ -566,6 +567,11 @@ static void hwif_register (ide_hwif_t *hwif)
/* register with global device tree */ /* register with global device tree */
strncpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE); strncpy(hwif->gendev.bus_id,hwif->name,BUS_ID_SIZE);
snprintf(hwif->gendev.name,DEVICE_NAME_SIZE,"IDE Controller"); snprintf(hwif->gendev.name,DEVICE_NAME_SIZE,"IDE Controller");
hwif->gendev.driver_data = hwif;
if (hwif->pci_dev)
hwif->gendev.parent = &hwif->pci_dev->dev;
else
hwif->gendev.parent = NULL; /* Would like to do = &device_legacy */
device_register(&hwif->gendev); device_register(&hwif->gendev);
if (hwif->mmio == 2) if (hwif->mmio == 2)
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/bitops.h> #include <linux/bitops.h>
#include <linux/bio.h> #include <linux/bio.h>
#include <linux/device.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -789,6 +790,7 @@ typedef struct ide_drive_s { ...@@ -789,6 +790,7 @@ typedef struct ide_drive_s {
unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */ unsigned autotune : 2; /* 1=autotune, 2=noautotune, 0=default */
unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */ unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */
unsigned ata_flash : 1; /* 1=present, 0=default */ unsigned ata_flash : 1; /* 1=present, 0=default */
unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */
unsigned addressing; /* : 3; unsigned addressing; /* : 3;
* 0=28-bit * 0=28-bit
* 1=48-bit * 1=48-bit
......
...@@ -471,18 +471,21 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p) ...@@ -471,18 +471,21 @@ static int count_and_copy_data_pages(struct pbe *pagedir_p)
int pfn; int pfn;
struct page *page; struct page *page;
#ifndef CONFIG_DISCONTIGMEM #ifdef CONFIG_DISCONTIGMEM
if (max_mapnr != num_physpages) panic("Discontingmem not supported");
panic("mapnr is not expected"); #else
BUG_ON (max_mapnr != num_physpages);
#endif #endif
for (pfn = 0; pfn < num_physpages; pfn++) { for (pfn = 0; pfn < max_mapnr; pfn++) {
page = pfn_to_page(pfn); page = pfn_to_page(pfn);
if (PageHighMem(page)) if (PageHighMem(page))
panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to <pavel@ucw.cz> and try again ;-)."); panic("Swsusp not supported on highmem boxes. Send 1GB of RAM to <pavel@ucw.cz> and try again ;-).");
if (!PageReserved(page)) { if (!PageReserved(page)) {
if (PageNosave(page)) if (PageNosave(page))
continue; continue;
if ((chunk_size=is_head_of_free_region(page))!=0) { if ((chunk_size=is_head_of_free_region(page))!=0) {
pfn += chunk_size - 1; pfn += chunk_size - 1;
continue; continue;
...@@ -776,9 +779,10 @@ void do_magic_resume_2(void) ...@@ -776,9 +779,10 @@ void do_magic_resume_2(void)
BUG_ON (nr_copy_pages_check != nr_copy_pages); BUG_ON (nr_copy_pages_check != nr_copy_pages);
BUG_ON (pagedir_order_check != pagedir_order); BUG_ON (pagedir_order_check != pagedir_order);
__flush_tlb_global(); /* Even mappings of "global" things (vmalloc) need to be fixed */
PRINTK( "Freeing prev allocated pagedir\n" ); PRINTK( "Freeing prev allocated pagedir\n" );
free_suspend_pagedir((unsigned long) pagedir_save); free_suspend_pagedir((unsigned long) pagedir_save);
__flush_tlb_global(); /* Even mappings of "global" things (vmalloc) need to be fixed */
drivers_resume(RESUME_ALL_PHASES); drivers_resume(RESUME_ALL_PHASES);
spin_unlock_irq(&suspend_pagedir_lock); spin_unlock_irq(&suspend_pagedir_lock);
...@@ -809,12 +813,10 @@ void do_magic_suspend_2(void) ...@@ -809,12 +813,10 @@ void do_magic_suspend_2(void)
barrier(); barrier();
mb(); mb();
drivers_resume(RESUME_PHASE2);
spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */ spin_lock_irq(&suspend_pagedir_lock); /* Done to disable interrupts */
mdelay(1000); mdelay(1000);
free_pages((unsigned long) pagedir_nosave, pagedir_order); free_pages((unsigned long) pagedir_nosave, pagedir_order);
drivers_resume(RESUME_PHASE1);
spin_unlock_irq(&suspend_pagedir_lock); spin_unlock_irq(&suspend_pagedir_lock);
mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME); mark_swapfiles(((swp_entry_t) {0}), MARK_SWAP_RESUME);
PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend); PRINTK(KERN_WARNING "%sLeaving do_magic_suspend_2...\n", name_suspend);
...@@ -1037,6 +1039,7 @@ static int bdev_write_page(struct block_device *bdev, long pos, void *buf) ...@@ -1037,6 +1039,7 @@ static int bdev_write_page(struct block_device *bdev, long pos, void *buf)
return 0; return 0;
#endif #endif
printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unimplemented...\n", name_resume, resume_file); printk(KERN_CRIT "%sWarning %s: Fixing swap signatures unimplemented...\n", name_resume, resume_file);
return 0;
} }
extern kdev_t __init name_to_kdev_t(const char *line); extern kdev_t __init name_to_kdev_t(const char *line);
......
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