diff -ruNp 623-generic-block-io.patch-old/kernel/power/block_io.h 
623-generic-block-io.patch-new/kernel/power/block_io.h
--- 623-generic-block-io.patch-old/kernel/power/block_io.h      1970-01-01 
10:00:00.000000000 +1000
+++ 623-generic-block-io.patch-new/kernel/power/block_io.h      2005-07-05 
23:48:59.000000000 +1000
@@ -0,0 +1,55 @@
+/*
+ * block_io.h
+ *
+ * Copyright 2004-2005 Nigel Cunningham <[EMAIL PROTECTED]>
+ *
+ * Distributed under GPLv2.
+ *
+ * This file contains declarations for functions exported from
+ * block_io.c, which contains low level io functions.
+ */
+
+/* 
+ * The maximum amount of I/O we submit at once.
+ */
+#define MAX_READAHEAD 1024
+
+/* Forward Declarations */
+
+/*
+ * submit_params
+ *
+ * The structure we use for tracking submitted I/O.
+ */
+struct submit_params {
+       swp_entry_t swap_address;
+       struct page * page;
+       struct block_device * dev;
+       long block[8];
+       int readahead_index;
+       struct submit_params * next;
+};
+
+
+/* 
+ * Our exported interface so the swapwriter and filewriter don't
+ * need these functions duplicated.
+ */
+struct suspend_bio_ops {
+       int (*set_block_size) (struct block_device * bdev, int size);
+       int (*get_block_size) (struct block_device * bdev);
+       int (*submit_io) (int rw, 
+               struct submit_params * submit_info, int syncio);
+       int (*bdev_page_io) (int rw, struct block_device * bdev, long pos,
+                       struct page * page);
+       void (*wait_on_readahead) (int readahead_index);
+       void (*check_io_stats) (void);
+       void (*reset_io_stats) (void);
+       void (*finish_all_io) (void);
+       int (*prepare_readahead) (int index);
+       void (*cleanup_readahead) (int index);
+       struct page ** readahead_pages;
+       int (*readahead_ready) (int readahead_index);
+};
+
+extern struct suspend_bio_ops suspend_bio_ops;
diff -ruNp 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c 
623-generic-block-io.patch-new/kernel/power/suspend_block_io.c
--- 623-generic-block-io.patch-old/kernel/power/suspend_block_io.c      
1970-01-01 10:00:00.000000000 +1000
+++ 623-generic-block-io.patch-new/kernel/power/suspend_block_io.c      
2005-07-05 23:48:59.000000000 +1000
@@ -0,0 +1,817 @@
+/*
+ * block_io.c
+ *
+ * Copyright 2004-2005 Nigel Cunningham <[EMAIL PROTECTED]>
+ *
+ * Distributed under GPLv2.
+ * 
+ * This file contains block io functions for suspend2. These are
+ * used by the swapwriter and it is planned that they will also
+ * be used by the NFSwriter.
+ *
+ */
+
+#include <linux/suspend.h>
+#include <linux/module.h>
+#include <linux/highmem.h>
+#include <linux/blkdev.h>
+#include <linux/bio.h>
+#include <linux/kthread.h>
+
+#include "suspend2_core/suspend.h"
+#include "suspend2_core/proc.h"
+#include "suspend2_core/plugins.h"
+#include "suspend2_core/utility.h"
+#include "suspend2_core/prepare_image.h"
+
+#include "block_io.h"
+
+/* Bits in struct io_info->flags */
+#define IO_WRITING 1
+#define IO_RESTORE_PAGE_PROT 2
+#define IO_AWAITING_READ 3
+#define IO_AWAITING_WRITE 4
+#define IO_AWAITING_SUBMIT 5
+#define IO_AWAITING_CLEANUP 6
+#define IO_HANDLE_PAGE_PROT 7
+
+#define MAX_OUTSTANDING_IO 1024
+
+/*
+ * ---------------------------------------------------------------
+ *
+ *     IO in progress information storage and helpers
+ *
+ * ---------------------------------------------------------------
+ */
+
+struct io_info {
+       struct bio * sys_struct;
+       long block[PAGE_SIZE/512];
+       struct page * buffer_page;
+       struct page * data_page;
+       unsigned long flags;
+       struct block_device * dev;
+       struct list_head list;
+       int readahead_index;
+       struct work_struct work;
+};
+
+/* Locks separated to allow better SMP support.
+ * An io_struct moves through the lists as follows.
+ * free -> submit_batch -> busy -> ready_for_cleanup -> free
+ */
+static LIST_HEAD(ioinfo_free);
+static spinlock_t ioinfo_free_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_ready_for_cleanup);
+static spinlock_t ioinfo_ready_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_submit_batch);
+static spinlock_t ioinfo_submit_lock = SPIN_LOCK_UNLOCKED;
+
+static LIST_HEAD(ioinfo_busy);
+static spinlock_t ioinfo_busy_lock = SPIN_LOCK_UNLOCKED;
+
+static atomic_t submit_batch;
+static int submit_batch_size = 64;
+static int submit_batched(void);
+
+struct task_struct * suspend_bio_task;
+
+/* [Max] number of I/O operations pending */
+static atomic_t outstanding_io;
+static int max_outstanding_io = 0;
+static atomic_t buffer_allocs, buffer_frees;
+
+/* [Max] number of pages used for above struct */
+static int infopages = 0;
+static int maxinfopages = 0;
+
+#define BITS_PER_UL (8 * sizeof(unsigned long))
+static volatile unsigned long suspend_readahead_flags[(MAX_READAHEAD + 
BITS_PER_UL - 1) / BITS_PER_UL];
+static spinlock_t suspend_readahead_flags_lock = SPIN_LOCK_UNLOCKED;
+static struct page * suspend_readahead_pages[MAX_READAHEAD];
+
+static unsigned long nr_schedule_calls[8];
+
+static char * sch_caller[] = {
+       "get_io_info_struct #1    ",
+       "get_io_info_struct #2    ",
+       "get_io_info_struct #3    ",
+       "suspend_finish_all_io    ",
+       "wait_on_one_page         ",
+       "submit                   ",
+       "start_one                ",
+       "suspend_wait_on_readahead",
+};
+
+static int __suspend_io_cleanup(void * data);
+
+/* cleanup_some_completed_io
+ *
+ * NB: This is designed so that multiple callers can be in here simultaneously.
+ */
+
+static void cleanup_some_completed_io(void)
+{
+       int num_cleaned = 0;
+       struct io_info * first;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioinfo_ready_lock, flags);
+       while(!list_empty(&ioinfo_ready_for_cleanup)) {
+               int result;
+               first = list_entry(ioinfo_ready_for_cleanup.next, struct 
io_info, list);
+
+               BUG_ON(!test_and_clear_bit(IO_AWAITING_CLEANUP, &first->flags));
+
+               list_del_init(&first->list);
+
+               spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+
+               result = __suspend_io_cleanup((void *) first);
+
+               spin_lock_irqsave(&ioinfo_ready_lock, flags);
+               if (result)
+                       continue;
+               num_cleaned++;
+               if (num_cleaned == submit_batch_size)
+                       break;
+       }
+       spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+}
+
+/* do_bio_wait
+ *
+ * Actions taken when we want some I/O to get run.
+ * 
+ * Submit any I/O that's batched up, unplug queues, schedule
+ * and clean up whatever we can.
+ */
+static void do_bio_wait(int caller)
+{
+       int device;
+       int num_submitted = 0;
+
+       nr_schedule_calls[caller]++;
+       
+       /* Don't want to wait on I/O we haven't submitted! */
+       num_submitted = submit_batched();
+
+       for (device = 0; device < MAX_SWAPFILES; device++) {
+               struct block_device * bdev = swap_info[device].bdev;
+               /* Check for a potential oops here */
+               if (bdev && bdev->bd_disk) {
+                       request_queue_t * q = bdev_get_queue(bdev);
+                       if (q && q->unplug_fn)
+                               q->unplug_fn(q);
+               }
+               /* kblockd_flush(); io_schedule(); */
+       }
+
+       schedule();
+
+       cleanup_some_completed_io();
+}
+
+/*
+ * cleanup_one
+ * 
+ * Description: Clean up after completing I/O on a page.
+ * Arguments:  struct io_info: Data for I/O to be completed.
+ */
+static inline void cleanup_one(struct io_info * io_info)
+{
+       struct page * buffer_page;
+       struct page * data_page;
+       char *buffer_address, *data_address;
+       int reading;
+
+       buffer_page = io_info->buffer_page;
+       data_page = io_info->data_page;
+
+       reading = test_bit(IO_AWAITING_READ, &io_info->flags);
+       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+               "Cleanup IO: [%p]\n", 
+               io_info);
+
+       if (reading && io_info->readahead_index == -1) {
+               /*
+                * Copy the page we read into the buffer our caller provided.
+                */
+               data_address = (char *) kmap(data_page);
+               buffer_address = (char *) kmap(buffer_page);
+               memcpy(data_address, buffer_address, PAGE_SIZE);
+               flush_dcache_page(data_page);
+               kunmap(data_page);
+               kunmap(buffer_page);
+       
+       }
+
+       if (!reading || io_info->readahead_index == -1) {
+               /* Sanity check */
+               if (page_count(buffer_page) != 2)
+                       printk(KERN_EMERG "Cleanup IO: Page count on page %p is 
%d. Not good!\n",
+                                       buffer_page, page_count(buffer_page));
+               put_page(buffer_page);
+               __free_pages(buffer_page, 0);
+               atomic_inc(&buffer_frees);
+       } else
+               put_page(buffer_page);
+       
+       bio_put(io_info->sys_struct);
+       io_info->sys_struct = NULL;
+       io_info->flags = 0;
+}
+
+/*
+ * get_io_info_struct
+ *
+ * Description:        Get an I/O struct.
+ * Returns:    Pointer to the struct prepared for use.
+ */
+static struct io_info * get_io_info_struct(void)
+{
+       unsigned long newpage = 0, flags;
+       struct io_info * this = NULL;
+       int remaining = 0;
+
+       do {
+               while (atomic_read(&outstanding_io) >= MAX_OUTSTANDING_IO)
+                       do_bio_wait(0);
+
+               /* Can start a new I/O. Is there a free one? */
+               if (!list_empty(&ioinfo_free)) {
+                       /* Yes. Grab it. */
+                       spin_lock_irqsave(&ioinfo_free_lock, flags);
+                       break;
+               }
+
+               /* No. Need to allocate a new page for I/O info structs. */
+               newpage = get_zeroed_page(GFP_ATOMIC);
+               if (!newpage) {
+                       do_bio_wait(1);
+                       continue;
+               }
+
+               suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 0,
+                               "[NewIOPage %lx]", newpage);
+               infopages++;
+               if (infopages > maxinfopages)
+                       maxinfopages++;
+
+               /* Prepare the new page for use. */
+               this = (struct io_info *) newpage;
+               remaining = PAGE_SIZE;
+               spin_lock_irqsave(&ioinfo_free_lock, flags);
+               while (remaining >= (sizeof(struct io_info))) {
+                       list_add_tail(&this->list, &ioinfo_free);
+                       this = (struct io_info *) (((char *) this) + 
+                                       sizeof(struct io_info));
+                       remaining -= sizeof(struct io_info);
+               }
+               break;
+       } while (1);
+
+       /*
+        * We have an I/O info struct. Remove it from the free list.
+        * It will be added to the submit or busy list later.
+        */
+       this = list_entry(ioinfo_free.next, struct io_info, list);
+       list_del_init(&this->list);
+       spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+       return this;
+}
+
+/*
+ * suspend_finish_all_io
+ *
+ * Description:        Finishes all IO and frees all IO info struct pages.
+ */
+static void suspend_finish_all_io(void)
+{
+       struct io_info * this, * next = NULL;
+       unsigned long flags;
+
+       /* Wait for all I/O to complete. */
+       while (atomic_read(&outstanding_io))
+               do_bio_wait(2);
+
+       spin_lock_irqsave(&ioinfo_free_lock, flags);
+       
+       /* 
+        * Two stages, to avoid using freed pages.
+        *
+        * First free all io_info structs on a page except the first.
+        */
+       list_for_each_entry_safe(this, next, &ioinfo_free, list) {
+               if (((unsigned long) this) & ~PAGE_MASK)
+                       list_del(&this->list);
+       }
+
+       /* 
+        * Now we have only one reference to each page, and can safely
+        * free pages, knowing we're not going to be trying to access the
+        * same page after freeing it.
+        */
+       list_for_each_entry_safe(this, next, &ioinfo_free, list) {
+               list_del(&this->list);
+               free_pages((unsigned long) this, 0);
+               infopages--;
+               suspend_message(SUSPEND_MEMORY, SUSPEND_VERBOSE, 0,
+                               "[FreedIOPage %lx]", this);
+       }
+       
+       spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+}
+
+/*
+ * wait_on_one_page
+ *
+ * Description:        Wait for a particular I/O to complete.
+ */
+static void wait_on_one_page(struct io_info * io_info)
+{
+       do { do_bio_wait(3); } while (io_info->flags);
+}
+
+/*
+ * suspend_reset_io_stats
+ *
+ * Description:        Reset all our sanity-checking statistics.
+ */
+static void suspend_reset_io_stats(void)
+{
+       int i;
+       
+       max_outstanding_io = 0;
+       maxinfopages = 0;
+       
+       for (i = 0; i < 8; i++)
+               nr_schedule_calls[i] = 0;
+}
+
+/*
+ * suspend_check_io_stats
+ *
+ * Description:        Check that our statistics look right and print
+ *             any debugging info wanted.
+ */
+static void suspend_check_io_stats(void)
+{
+       int i;
+
+       BUG_ON(atomic_read(&outstanding_io));
+       BUG_ON(infopages);
+       BUG_ON(!list_empty(&ioinfo_submit_batch));
+       BUG_ON(!list_empty(&ioinfo_busy));
+       BUG_ON(!list_empty(&ioinfo_ready_for_cleanup));
+       BUG_ON(!list_empty(&ioinfo_free));
+       BUG_ON(atomic_read(&buffer_allocs) != atomic_read(&buffer_frees));
+
+       if (atomic_read(&outstanding_io))
+               suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+                       "Outstanding_io after writing is %d.\n",
+                       atomic_read(&outstanding_io));
+       suspend_message(SUSPEND_WRITER, SUSPEND_LOW, 0,
+                       "Maximum outstanding_io was %d.\n",
+                       max_outstanding_io);
+       if (infopages)
+               suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+                               "Info pages is %d.\n",
+                               infopages);
+       suspend_message(SUSPEND_WRITER, SUSPEND_LOW, 0,
+                       "Max info pages was %d.\n",
+                       maxinfopages);
+       if (atomic_read(&buffer_allocs) != atomic_read(&buffer_frees))
+               suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+                       "Buffer allocs (%d) != buffer frees (%d)",
+                               atomic_read(&buffer_allocs),
+                               atomic_read(&buffer_frees));
+       for(i = 0; i < 8; i++)
+               suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+                       "Nr schedule calls %s: %lu.\n", sch_caller[i], 
nr_schedule_calls[i]);
+}
+
+/* __suspend_io_cleanup
+ */
+
+static int __suspend_io_cleanup(void * data)
+{
+       struct io_info * io_info = (struct io_info *) data;
+       int readahead_index;
+       unsigned long flags;
+
+       /*
+        * If this I/O was a readahead, remember its index.
+        */
+       readahead_index = io_info->readahead_index;
+
+       /*
+        * Add it to the free list.
+        */
+       list_del_init(&io_info->list);
+       
+       /*
+        * Do the cleanup.
+        */
+       cleanup_one(io_info);
+
+       /*
+        * Record the readahead as done.
+        */
+       if (readahead_index > -1) {
+               int index = readahead_index/(8 * sizeof(unsigned long));
+               int bit = readahead_index - (index * 8 * sizeof(unsigned long));
+               spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
+               set_bit(bit, &suspend_readahead_flags[index]);
+               spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
+       }
+
+       spin_lock_irqsave(&ioinfo_free_lock, flags);
+       list_add_tail(&io_info->list, &ioinfo_free);
+       spin_unlock_irqrestore(&ioinfo_free_lock, flags);
+       
+       /* Important: Must be last thing we do to avoid a race with
+        * finish_all_io when using keventd to do the cleanup */
+       atomic_dec(&outstanding_io);
+
+       return 0;
+}
+
+/*
+ * suspend_end_bio
+ *
+ * Description:        Function called by block driver from interrupt context 
when I/O
+ *             is completed. This is the reason we use spinlocks in
+ *             manipulating the io_info lists.                 
+ *             Nearly the fs/buffer.c version, but we want to mark the page as 
+ *             done in our own structures too.
+ */
+
+static int suspend_end_bio(struct bio * bio, unsigned int num, int err)
+{
+       struct io_info *io_info = (struct io_info *) bio->bi_private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ioinfo_busy_lock, flags);
+       list_del_init(&io_info->list);
+       spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
+
+       set_bit(IO_AWAITING_CLEANUP, &io_info->flags);
+               
+       spin_lock_irqsave(&ioinfo_ready_lock, flags);
+       list_add_tail(&io_info->list, &ioinfo_ready_for_cleanup);
+       spin_unlock_irqrestore(&ioinfo_ready_lock, flags);
+       return 0;
+}
+
+/**
+ *     submit - submit BIO request.
+ *     @rw:    READ or WRITE.
+ *     @io_info: IO info structure.
+ *
+ *     Based on Patrick's pmdisk code from long ago:
+ *     "Straight from the textbook - allocate and initialize the bio.
+ *     If we're writing, make sure the page is marked as dirty.
+ *     Then submit it and carry on."
+ *
+ *     With a twist, though - we handle block_size != PAGE_SIZE.
+ *     Caller has already checked that our page is not fragmented.
+ */
+
+static int submit(int rw, struct io_info * io_info)
+{
+       int error = 0;
+       struct bio * bio = NULL;
+       unsigned long flags;
+
+       while (!bio) {
+               bio = bio_alloc(GFP_ATOMIC,1);
+               if (!bio)
+                       do_bio_wait(4);
+       }
+
+       bio->bi_bdev = io_info->dev;
+       bio->bi_sector = io_info->block[0] * (io_info->dev->bd_block_size >> 9);
+       bio->bi_private = io_info;
+       bio->bi_end_io = suspend_end_bio;
+       io_info->sys_struct = bio;
+
+       if (bio_add_page(bio, io_info->buffer_page, PAGE_SIZE, 0) < PAGE_SIZE) {
+               printk("ERROR: adding page to bio at %ld\n",
+                               io_info->block[0]);
+               bio_put(bio);
+               return -EFAULT;
+       }
+
+       if (rw == WRITE)
+               bio_set_pages_dirty(bio);
+
+       spin_lock_irqsave(&ioinfo_busy_lock, flags);
+       list_add_tail(&io_info->list, &ioinfo_busy);
+       spin_unlock_irqrestore(&ioinfo_busy_lock, flags);
+       
+       submit_bio(rw,bio);
+
+       return error;
+}
+
+/*
+ * suspend_set_block_size
+ *
+ * Description: Set the blocksize for a bdev. This is a separate function
+ *             because we have different versions for 2.4 and 2.6.
+ */
+static int suspend_set_block_size(struct block_device * bdev, int size)
+{
+       return set_blocksize(bdev, size);
+}
+
+static int suspend_get_block_size(struct block_device * bdev)
+{
+       return block_size(bdev);
+}
+
+/* 
+ * submit a batch
+ */
+static int submit_batched(void)
+{
+       struct io_info * first;
+       unsigned long flags;
+       int num_submitted = 0;
+
+       spin_lock_irqsave(&ioinfo_submit_lock, flags);
+       while(!list_empty(&ioinfo_submit_batch)) {
+               first = list_entry(ioinfo_submit_batch.next, struct io_info, 
list);
+
+               BUG_ON(!test_and_clear_bit(IO_AWAITING_SUBMIT, &first->flags));
+
+               list_del_init(&first->list);
+
+               atomic_dec(&submit_batch);
+
+               spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+               if (test_bit(IO_AWAITING_READ, &first->flags))
+                       submit(READ, first);
+               else
+                       submit(WRITE, first);
+
+               spin_lock_irqsave(&ioinfo_submit_lock, flags);
+               
+               num_submitted++;
+               if (num_submitted == submit_batch_size)
+                       break;
+       }
+       spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+       return num_submitted;
+}
+static void add_to_batch(struct io_info * io_info)
+{
+       unsigned long flags;
+       
+       set_bit(IO_AWAITING_SUBMIT, &io_info->flags);
+
+       /* Put our prepared I/O struct on the batch list. */
+       spin_lock_irqsave(&ioinfo_submit_lock, flags);
+       list_add_tail(&io_info->list, &ioinfo_submit_batch);
+       spin_unlock_irqrestore(&ioinfo_submit_lock, flags);
+
+       atomic_inc(&submit_batch);
+
+       if ((!suspend_bio_task) && (atomic_read(&submit_batch) >= 
submit_batch_size))
+               submit_batched();
+}
+/*
+ * start_one
+ *
+ * Description:        Prepare and start a read or write operation.
+ *             Note that we use our own buffer for reading or writing.
+ *             This simplifies doing readahead and asynchronous writing.
+ *             We can begin a read without knowing the location into which
+ *             the data will eventually be placed, and the buffer passed
+ *             for a write can be reused immediately (essential for the
+ *             plugins system).
+ *             Failure? What's that?
+ * Returns:    The io_info struct created.
+ */
+static struct io_info * start_one(int rw, struct submit_params * submit_info)
+{
+       struct io_info * io_info = get_io_info_struct();
+       unsigned long buffer_virt = 0;
+       char * to, * from;
+       struct page * buffer_page;
+
+       if (!io_info)
+               return NULL;
+
+       /* Get our local buffer */
+       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
+                       "Start_IO: [%p]", io_info);
+       
+       /* Copy settings to the io_info struct */
+       io_info->data_page = submit_info->page;
+       io_info->readahead_index = submit_info->readahead_index;
+
+       if (io_info->readahead_index == -1) {
+               while (!(buffer_virt = get_zeroed_page(GFP_ATOMIC)))
+                       do_bio_wait(5);
+
+               atomic_inc(&buffer_allocs);
+               suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 0,
+                               "[ALLOC BUFFER]->%d",
+                               real_nr_free_pages());
+               buffer_page = virt_to_page(buffer_virt);
+       
+               io_info->buffer_page = buffer_page;
+       } else {
+               unsigned long flags;
+               int index = io_info->readahead_index/(8 * sizeof(unsigned 
long));
+               int bit = io_info->readahead_index - index * 8 * 
sizeof(unsigned long);
+
+               spin_lock_irqsave(&suspend_readahead_flags_lock, flags);
+               clear_bit(bit, &suspend_readahead_flags[index]);
+               spin_unlock_irqrestore(&suspend_readahead_flags_lock, flags);
+
+               io_info->buffer_page = buffer_page = submit_info->page;
+       }
+
+       /* If writing, copy our data. The data is probably in
+        * lowmem, but we cannot be certain. If there is no
+        * compression/encryption, we might be passed the
+        * actual source page's address. */
+       if (rw == WRITE) {
+               set_bit(IO_WRITING, &io_info->flags);
+
+               to = (char *) buffer_virt;
+               from = kmap_atomic(io_info->data_page, KM_USER1);
+               memcpy(to, from, PAGE_SIZE);
+               flush_dcache_page(io_info->data_page);
+               flush_dcache_page(buffer_page);
+               kunmap_atomic(from, KM_USER1);
+       }
+
+       /* Submit the page */
+       get_page(buffer_page);
+       
+       io_info->dev = submit_info->dev;
+       io_info->block[0] = submit_info->block[0];
+
+       if (rw == READ)
+               set_bit(IO_AWAITING_READ, &io_info->flags);
+       else
+               set_bit(IO_AWAITING_WRITE, &io_info->flags);
+
+       suspend_message(SUSPEND_WRITER, SUSPEND_HIGH, 1,
+                       "-> (PRE BRW) %d\n",
+                       real_nr_free_pages());
+
+       if (submit_batch_size > 1)
+               add_to_batch(io_info);
+       else
+               submit(rw, io_info);
+       
+       atomic_inc(&outstanding_io);
+       if (atomic_read(&outstanding_io) > max_outstanding_io)
+               max_outstanding_io++;
+       
+       return io_info;
+}
+
+static int suspend_do_io(int rw, 
+               struct submit_params * submit_info, int syncio)
+{
+       struct io_info * io_info = start_one(rw, submit_info);
+       if (!io_info)
+               return 1;
+       else if (syncio)
+               wait_on_one_page(io_info);
+
+       /* If we were the only one, clean everything up */
+       if (!atomic_read(&outstanding_io))
+               suspend_finish_all_io();
+       return 0;
+} 
+
+/* We used to use bread here, but it doesn't correctly handle
+ * blocksize != PAGE_SIZE. Now we create a submit_info to get the data we
+ * want and use our normal routines (synchronously).
+ */
+
+static int suspend_bdev_page_io(int rw, struct block_device * bdev, long pos,
+               struct page * page)
+{
+       struct submit_params submit_info;
+
+       submit_info.page = page;
+       submit_info.dev = bdev;
+       submit_info.block[0] = pos;
+       submit_info.readahead_index = -1;
+       return suspend_do_io(rw, &submit_info, 1);
+}
+
+/*
+ * wait_on_readahead
+ *
+ * Wait until a particular readahead is ready.
+ */
+static void suspend_wait_on_readahead(int readahead_index)
+{
+       int index = readahead_index/(8 * sizeof(unsigned long));
+       int bit = readahead_index - index * 8 * sizeof(unsigned long);
+
+       /* read_ahead_index is the one we want to return */
+       while (!test_bit(bit, &suspend_readahead_flags[index]))
+               do_bio_wait(6);
+}
+
+/*
+ * readahead_done
+ *
+ * Returns whether the readahead requested is ready.
+ */
+
+static int suspend_readahead_ready(int readahead_index)
+{
+       int index = readahead_index/(8 * sizeof(unsigned long));
+       int bit = readahead_index - (index * 8 * sizeof(unsigned long));
+
+       return test_bit(bit, &suspend_readahead_flags[index]);
+}
+
+/* suspend_readahead_prepare
+ * Set up for doing readahead on an image */
+static int suspend_prepare_readahead(int index)
+{
+       unsigned long new_page = get_zeroed_page(GFP_ATOMIC);
+
+       if(!new_page)
+               return -ENOMEM;
+
+       suspend_bio_ops.readahead_pages[index] = virt_to_page(new_page);
+       return 0;
+}
+
+/* suspend_readahead_cleanup
+ * Clean up structures used for readahead */
+static void suspend_cleanup_readahead(int page)
+{
+       __free_pages(suspend_bio_ops.readahead_pages[page], 0);
+       suspend_bio_ops.readahead_pages[page] = 0;
+       return;
+}
+
+static unsigned long suspend_bio_memory_needed(void)
+{
+       /* We want to have at least enough memory so as to have 128 I/O
+        * transactions on the fly at once. If we can to more, fine. */
+       return (128 * (PAGE_SIZE + sizeof(struct request) +
+                               sizeof(struct bio) + sizeof(struct io_info)));
+}
+
+struct suspend_bio_ops suspend_bio_ops = {
+       .set_block_size = suspend_set_block_size,
+       .get_block_size = suspend_get_block_size,
+       .submit_io = suspend_do_io,
+       .bdev_page_io = suspend_bdev_page_io,
+       .prepare_readahead = suspend_prepare_readahead,
+       .cleanup_readahead = suspend_cleanup_readahead,
+       .readahead_pages = suspend_readahead_pages,
+       .wait_on_readahead = suspend_wait_on_readahead,
+       .check_io_stats = suspend_check_io_stats,
+       .reset_io_stats = suspend_reset_io_stats,
+       .finish_all_io = suspend_finish_all_io,
+       .readahead_ready = suspend_readahead_ready,
+};
+
+static struct suspend_plugin_ops suspend_blockwriter_ops = 
+{
+       .name                                   = "Block I/O",
+       .type                                   = MISC_PLUGIN,
+       .module                                 = THIS_MODULE,
+       .memory_needed                          = suspend_bio_memory_needed,
+};
+
+static __init int suspend_block_io_load(void)
+{
+       return suspend_register_plugin(&suspend_blockwriter_ops);
+}
+
+#ifdef MODULE
+static __exit void suspend_block_io_unload(void)
+{
+       suspend_unregister_plugin(&suspend_blockwriter_ops);
+}
+
+module_init(suspend_block_io_load);
+module_exit(suspend_block_io_unload);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nigel Cunningham");
+MODULE_DESCRIPTION("Suspend2 block io functions");
+#else
+late_initcall(suspend_block_io_load);
+#endif

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to