From: Nigel Cunningham <ncunningham@linuxmail.org>
To: Linux Kernel Mailing List <linux-kernel@vger.kernel.org>
Subject: Suspend 2 merge: 27/51: Block I/O module.
Date: Wed, 24 Nov 2004 23:59:23 +1100 [thread overview]
Message-ID: <1101296756.5805.296.camel@desktop.cunninghams> (raw)
In-Reply-To: <1101292194.5805.180.camel@desktop.cunninghams>
This is the code that does all the really hard work in reading and
writing the image. It provides full asynchronous I/O, and in combination
with the layer above, readahead where I/O needs to be synchronous (image
decompression). I/O is also batched to further improve throughput. Some
of the key parameters are user tunable, as the best setting varies from
computer to computer.
diff -ruN 812-suspend2-block-io-module-old/kernel/power/suspend_block_io.c 812-suspend2-block-io-module-new/kernel/power/suspend_block_io.c
--- 812-suspend2-block-io-module-old/kernel/power/suspend_block_io.c 1970-01-01 10:00:00.000000000 +1000
+++ 812-suspend2-block-io-module-new/kernel/power/suspend_block_io.c 2004-11-23 22:18:49.000000000 +1100
@@ -0,0 +1,827 @@
+/*
+ * block_io.c
+ *
+ * Copyright 2004 Nigel Cunningham <ncunningham@linuxmail.org>
+ *
+ * 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 "suspend.h"
+#include "block_io.h"
+#include "proc.h"
+#include "plugins.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_CLEANUP_IN_PROGRESS 5
+#define IO_HANDLE_PAGE_PROT 6
+
+#define USE_KEVENTD
+//#define TUNE_BATCHING
+
+/*
+ * ---------------------------------------------------------------
+ *
+ * IO in progress information storage and helpers
+ *
+ * ---------------------------------------------------------------
+ */
+
+struct io_info {
+ struct bio * sys_struct;
+ long blocks[PAGE_SIZE/512];
+ struct page * buffer_page;
+ struct page * data_page;
+ unsigned long flags;
+ struct block_device * dev;
+ int blocks_used;
+ int block_size;
+ struct list_head list;
+ int readahead_index;
+ struct work_struct work;
+};
+
+static LIST_HEAD(ioinfo_free);
+static LIST_HEAD(ioinfo_ready_for_cleanup);
+static LIST_HEAD(ioinfo_busy);
+static LIST_HEAD(ioinfo_submit_batch);
+static spinlock_t ioinfo_lists_lock = SPIN_LOCK_UNLOCKED;
+
+static int submit_batch = 0, submit_batch_size = 32;
+static void 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 int buffer_allocs, buffer_frees;
+
+/* [Max] number of pages used for above struct */
+static int infopages = 0;
+static int maxinfopages = 0;
+
+static volatile unsigned long suspend_readahead_flags[((MAX_READAHEAD + (8 * sizeof(unsigned long) - 1)) / (8 * sizeof(unsigned long)))];
+static spinlock_t suspend_readahead_flags_lock = SPIN_LOCK_UNLOCKED;
+static struct page * suspend_readahead_pages[MAX_READAHEAD];
+
+static unsigned long nr_schedule_calls[6];
+static unsigned long bio_jiffies = 0;
+
+static char * sch_caller[] = {
+ "get_io_info_struct ",
+ "suspend_finish_all_io ",
+ "wait_on_one_page ",
+ "submit ",
+ "start_one ",
+ "suspend_wait_on_readahead",
+};
+
+static void suspend_io_cleanup(void * data);
+
+static void do_bio_wait(int caller)
+{
+#ifndef USE_KEVENTD
+ int num_cleaned = 0;
+ struct io_info * this, * next = NULL;
+#endif
+ int device;
+
+ nr_schedule_calls[caller]++;
+
+ /* Don't want to wait on I/O we haven't submitted! */
+ submit_batched();
+
+#ifndef USE_KEVENTD
+ if (!list_empty(&ioinfo_ready_for_cleanup))
+ list_for_each_entry_safe(this, next, &ioinfo_ready_for_cleanup, list) {
+ suspend_io_cleanup((void *) this);
+ num_cleaned++;
+ if (num_cleaned == 32)
+ break;
+ }
+#endif
+ for (device = 0; device < MAX_SWAPFILES; device++) {
+ struct block_device * bdev = swap_info[device].bdev;
+ if (bdev) {
+ request_queue_t * q = bdev_get_queue(bdev);
+ if (q && q->unplug_fn)
+ q->unplug_fn(q);
+ }
+ /* kblockd_flush(); io_schedule(); */
+ }
+ schedule();
+}
+
+/*
+ * 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;
+
+ /*
+ * Already being cleaned up? Can't happen while we're single
+ * threaded, but a good check for later.
+ */
+
+ if (test_and_set_bit(IO_CLEANUP_IN_PROGRESS, &io_info->flags))
+ return;
+
+ 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 is %d. Not good!\n",
+ page_count(buffer_page));
+ put_page(buffer_page);
+ __free_pages(buffer_page, 0);
+ buffer_frees++;
+ } else
+ put_page(buffer_page);
+
+ atomic_dec(&outstanding_io);
+ 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 {
+ /* Have we reached our number-of-IOs-activate-at-one limit? */
+ if ((max_async_ios) && (atomic_read(&outstanding_io) >= max_async_ios)) {
+ do_bio_wait(0);
+ continue;
+ }
+
+ /* Can start a new I/O. Is there a free one? */
+ if (!list_empty(&ioinfo_free)) {
+ /* Yes. Grab it. */
+ spin_lock_irqsave(&ioinfo_lists_lock, flags);
+ break;
+ }
+
+ /* No. Need to allocate a new page for I/O info structs. */
+ newpage = get_zeroed_page(GFP_ATOMIC);
+ if (!newpage)
+ 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_lists_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. Move it to the busy list. */
+ this = list_entry(ioinfo_free.next, struct io_info, list);
+ list_move_tail(&this->list, &ioinfo_busy);
+ spin_unlock_irqrestore(&ioinfo_lists_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;
+
+ /* Submit any pending write batch */
+ submit_batched();
+
+ /* Wait for all I/O to complete. */
+ while (atomic_read(&outstanding_io))
+ do_bio_wait(1);
+
+ /*
+ * We're single threaded and all I/O is completed, so we shouldn't
+ * need to use the spinlock, but let's be safe.
+ */
+ spin_lock_irqsave(&ioinfo_lists_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_lists_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(2); } 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;
+ buffer_allocs = buffer_frees = 0;
+
+ for (i = 0; i < 6; i++)
+ nr_schedule_calls[i] = 0;
+ bio_jiffies = 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(buffer_allocs != buffer_frees);
+ BUG_ON(!list_empty(&ioinfo_busy));
+ BUG_ON(!list_empty(&ioinfo_ready_for_cleanup));
+ BUG_ON(!list_empty(&ioinfo_free));
+
+ 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 (buffer_allocs != buffer_frees)
+ suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+ "Buffer allocs (%d) != buffer frees (%d)",
+ buffer_allocs,
+ buffer_frees);
+ for(i = 0; i < 6; i++)
+ suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+ "Nr schedule calls %s: %lu.\n", sch_caller[i], nr_schedule_calls[i]);
+ suspend_message(SUSPEND_WRITER, SUSPEND_MEDIUM, 0,
+ "Jiffies waiting for bio calls:%lu.\n", bio_jiffies);
+}
+
+/* suspend_io_cleanup
+ */
+
+static void 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;
+
+ /*
+ * 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);
+ }
+
+ /*
+ * Add it to the free list.
+ */
+ spin_lock_irqsave(&ioinfo_lists_lock, flags);
+ list_move_tail(&io_info->list, &ioinfo_free);
+ spin_unlock_irqrestore(&ioinfo_lists_lock, flags);
+}
+
+/*
+ * 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_lists_lock, flags);
+ list_move_tail(&io_info->list, &ioinfo_ready_for_cleanup);
+ spin_unlock_irqrestore(&ioinfo_lists_lock, flags);
+
+#ifdef USE_KEVENTD
+ INIT_WORK(&io_info->work, suspend_io_cleanup, (void *) io_info);
+ schedule_work(&io_info->work);
+#endif
+ return 0;
+}
+
+/**
+ * submit - submit BIO request.
+ * @rw: READ or WRITE.
+ * @io_info: IO info structure.
+ *
+ * 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.
+ */
+
+static int submit(int rw, struct io_info * io_info)
+{
+ int error = 0;
+ struct bio * bio = NULL;
+ unsigned long j1 = jiffies;
+
+ while (!bio) {
+ bio = bio_alloc(GFP_ATOMIC,1);
+ if (!bio)
+ do_bio_wait(3);
+ }
+
+ bio->bi_sector = io_info->blocks[0] << (PAGE_SHIFT - 9);
+ bio->bi_bdev = io_info->dev;
+ 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->blocks[0]);
+ bio_put(bio);
+ return -EFAULT;
+ }
+
+ if (rw == WRITE)
+ bio_set_pages_dirty(bio);
+ submit_bio(rw,bio);
+ bio_jiffies += jiffies - j1;
+ 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);
+}
+
+/*
+ * We don't need to worry about new requests being added to the list;
+ * we're called from process context
+ */
+static void submit_batched(void)
+{
+ unsigned long flags;
+ struct io_info * this, * next = NULL;
+
+ list_for_each_entry_safe(this, next, &ioinfo_submit_batch, list) {
+ spin_lock_irqsave(&ioinfo_lists_lock, flags);
+ list_move_tail(&this->list, &ioinfo_busy);
+ spin_unlock_irqrestore(&ioinfo_lists_lock, flags);
+ if (test_bit(IO_AWAITING_READ, &this->flags))
+ submit(READ, this);
+ else
+ submit(WRITE, this);
+ }
+ submit_batch = 0;
+}
+static void add_to_batch(struct io_info * io_info)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioinfo_lists_lock, flags);
+ /* We have an I/O info struct. Move it to the batch list. */
+ list_move_tail(&io_info->list, &ioinfo_submit_batch);
+ spin_unlock_irqrestore(&ioinfo_lists_lock, flags);
+
+ submit_batch++;
+
+ if (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;
+ int i;
+
+ 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(4);
+
+ 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;
+ for (i = 0; i < submit_info->blocks_used; i++)
+ io_info->blocks[i] = submit_info->blocks[i];
+ io_info->blocks_used = submit_info->blocks_used;
+ io_info->block_size = PAGE_SIZE / submit_info->blocks_used;
+
+ 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.blocks[0] = pos;
+ submit_info.blocks_used = 1;
+ 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(5);
+}
+
+/*
+ * 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) {
+ printk("No page for readahead %d.\n", index);
+ 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)
+{
+ return (REAL_MAX_ASYNC * (PAGE_SIZE + sizeof(struct request) +
+ sizeof(struct bio) + sizeof(struct io_info)));
+}
+
+#if 0
+static int suspend_bio_kthread(void * data)
+{
+ return 0;
+}
+
+static int start_suspend_bio_thread(void)
+{
+
+ suspend_bio_task = kthread_run(suspend_bio_kthread, NULL,
+ PF_NOFREEZE, "suspend_bio");
+
+ if (IS_ERR(suspend_bio_task)) {
+ printk("suspend_bio thread could not be started.\n");
+ return -EPERM;
+ }
+
+ return 0;
+}
+
+static void end_suspend_bio_thread(void)
+{
+}
+#endif
+
+static struct suspend_proc_data proc_params[] = {
+ { .filename = "async_io_limit",
+ .permissions = PROC_RW,
+ .type = SUSPEND_PROC_DATA_INTEGER,
+ .data = {
+ .integer = {
+ .variable = &max_async_ios,
+ .minimum = 1,
+ .maximum = MAX_READAHEAD,
+ }
+ }
+ },
+
+#ifdef CONFIG_SOFTWARE_SUSPEND_DEBUG
+#ifdef TUNE_BATCHING
+ { .filename = "submit_batch_size",
+ .permissions = PROC_RW,
+ .type = SUSPEND_PROC_DATA_INTEGER,
+ .data = {
+ .integer = {
+ .variable = &submit_batch_size,
+ .minimum = 1,
+ .maximum = 512,
+ }
+ }
+ },
+#endif
+#endif
+};
+
+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,
+};
+
+EXPORT_SYMBOL(suspend_bio_ops);
+
+static struct suspend_plugin_ops suspend_blockwriter_ops =
+{
+ .name = "Block I/O",
+ .type = MISC_PLUGIN,
+ //.initialise = start_suspend_bio_thread,
+ //.cleanup = end_suspend_bio_thread,
+ .memory_needed = suspend_bio_memory_needed,
+};
+
+static __init int suspend_block_io_load(void)
+{
+ int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+ int result;
+
+ if (!(result = suspend_register_plugin(&suspend_blockwriter_ops))) {
+ for (i=0; i< numfiles; i++)
+ suspend_register_procfile(&proc_params[i]);
+ }
+
+ return result;
+}
+
+#ifdef MODULE
+static __exit void suspend_block_io_unload(void)
+{
+ int i, numfiles = sizeof(proc_params) / sizeof(struct suspend_proc_data);
+
+ for (i=0; i< numfiles; i++)
+ suspend_unregister_procfile(&proc_params[i]);
+ 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
next prev parent reply other threads:[~2004-11-24 15:29 UTC|newest]
Thread overview: 241+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-24 12:56 Suspend 2 merge Nigel Cunningham
2004-11-24 12:56 ` Suspend2 merge: 1/51: Device trees Nigel Cunningham
2004-11-24 12:56 ` Suspend2 merge: 2/51: Find class by name Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 3/51: e820 table support Nigel Cunningham
2004-11-25 16:53 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 4/51: Get module list Nigel Cunningham
2004-11-25 16:56 ` Pavel Machek
2004-11-25 21:25 ` Nigel Cunningham
2004-11-25 21:32 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 5/51: Workthread freezer support Nigel Cunningham
2004-11-25 16:57 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 7/51: Reboot handler hook Nigel Cunningham
2004-11-24 13:07 ` Christoph Hellwig
2004-11-24 20:19 ` Nigel Cunningham
2004-11-25 2:37 ` Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 8/51: /proc/acpi/sleep hook Nigel Cunningham
2004-11-24 13:13 ` Christoph Hellwig
2004-11-24 12:57 ` Suspend 2 merge: 9/51: init/* changes Nigel Cunningham
2004-11-25 17:07 ` Pavel Machek
2004-11-25 21:36 ` Nigel Cunningham
2004-11-25 21:45 ` Pavel Machek
2004-11-25 21:51 ` Nigel Cunningham
2004-11-25 21:58 ` Pavel Machek
2004-11-25 22:03 ` Nigel Cunningham
2004-11-25 22:30 ` Pavel Machek
2004-11-27 2:14 ` Matthew Garrett
2004-11-27 7:22 ` Pavel Machek
2004-11-27 9:31 ` Herbert Xu
2004-11-27 13:21 ` Matthew Garrett
2004-11-27 16:20 ` Pavel Machek
2004-11-28 22:43 ` Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge: 10/51: Exports for suspend built as modules Nigel Cunningham
2004-11-24 13:12 ` Christoph Hellwig
2004-11-24 21:52 ` Nigel Cunningham
2004-11-24 14:44 ` Ingo Molnar
2004-11-24 20:46 ` Nigel Cunningham
2004-11-25 18:07 ` Pavel Machek
2004-11-25 21:40 ` Nigel Cunningham
2004-11-25 21:50 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 11/51: Export vt functions Nigel Cunningham
2004-11-24 12:57 ` Suspend 2 merge:L 12/51: Disable OOM killer when suspending Nigel Cunningham
2004-11-25 18:12 ` Pavel Machek
2004-11-25 21:47 ` Nigel Cunningham
2004-11-25 21:54 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 13/51: Disable highmem tlb flush for copyback Nigel Cunningham
2004-11-25 18:13 ` Pavel Machek
2004-11-24 12:57 ` Suspend 2 merge: 14/51: Disable page alloc failure message when suspending Nigel Cunningham
2004-11-24 14:15 ` Christoph Hellwig
2004-11-24 20:46 ` Nigel Cunningham
2004-11-24 16:00 ` Dave Hansen
2004-11-24 21:06 ` Nigel Cunningham
2004-11-24 22:25 ` Dave Hansen
2004-11-25 18:15 ` Pavel Machek
2004-11-25 21:49 ` Nigel Cunningham
2004-11-25 21:56 ` Pavel Machek
2004-11-25 22:46 ` Nigel Cunningham
2004-11-25 23:22 ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 15/51: Disable pdflush during suspend Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 16/51: Disable cache reaping " Nigel Cunningham
2004-11-25 18:18 ` Pavel Machek
2004-11-25 22:00 ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 17/51: Disable MCE checking " Nigel Cunningham
2004-11-25 18:19 ` Pavel Machek
2004-11-25 22:05 ` Nigel Cunningham
2004-11-25 22:31 ` Pavel Machek
2004-11-25 22:38 ` Nigel Cunningham
2004-11-25 22:45 ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 18/51: Debug page_alloc support Nigel Cunningham
2004-11-24 16:02 ` Dave Hansen
2004-11-24 20:17 ` Nigel Cunningham
2004-11-24 22:26 ` Dave Hansen
2004-11-25 18:21 ` Pavel Machek
2004-11-25 22:06 ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 19/51: Remove MTRR sysdev support Nigel Cunningham
2004-11-24 16:27 ` Zwane Mwaikambo
2004-11-24 20:17 ` Nigel Cunningham
2004-11-25 18:22 ` Pavel Machek
2004-11-28 22:34 ` Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 20/51: Timer freezer (experimental) Nigel Cunningham
2004-11-24 12:58 ` Suspend 2 merge: 21/51: Refrigerator upgrade Nigel Cunningham
2004-11-25 18:33 ` Pavel Machek
2004-11-25 22:10 ` Nigel Cunningham
2004-11-25 22:36 ` Pavel Machek
2004-11-25 22:49 ` Nigel Cunningham
2004-11-25 23:25 ` Pavel Machek
2004-11-25 23:49 ` Nigel Cunningham
2004-11-26 0:05 ` Pavel Machek
2004-11-26 0:12 ` Nigel Cunningham
2004-11-26 0:18 ` Pavel Machek
2004-11-27 17:18 ` Pavel Machek
2004-11-26 21:00 ` Christoph Hellwig
2004-11-24 12:58 ` Suspend 2 merge: 22/51: Suspend2 lowlevel code Nigel Cunningham
2004-11-24 16:42 ` Zwane Mwaikambo
2004-11-24 21:20 ` Nigel Cunningham
2004-11-24 21:55 ` Zwane Mwaikambo
2004-11-24 21:56 ` Nigel Cunningham
2004-11-25 18:39 ` Pavel Machek
2004-11-25 22:15 ` Nigel Cunningham
2004-11-25 22:38 ` Pavel Machek
2004-11-24 12:58 ` Suspend 2 merge: 23/51: PPC support Nigel Cunningham
2004-11-25 18:40 ` Pavel Machek
2004-11-25 22:15 ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 24/51: Keyboard and serial console hooks Nigel Cunningham
2004-11-24 13:29 ` Christoph Hellwig
2004-11-24 18:47 ` Yaroslav Rastrigin
2004-11-24 21:38 ` Nigel Cunningham
2004-11-24 21:57 ` Jan Rychter
2004-11-24 23:02 ` Christoph Hellwig
2004-11-25 1:22 ` Jan Rychter
2004-11-25 10:08 ` Christoph Hellwig
2004-11-26 20:21 ` pb
2004-11-25 19:28 ` Pavel Machek
2004-11-28 22:34 ` Nigel Cunningham
2004-11-28 23:39 ` Pavel Machek
2004-11-29 22:15 ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 25/51: Documentation Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 26/51: Kconfig and makefile Nigel Cunningham
2004-11-24 16:34 ` Roman Zippel
2004-11-24 21:11 ` Nigel Cunningham
2004-11-24 21:46 ` Roman Zippel
2004-11-24 21:53 ` Nigel Cunningham
2004-11-25 2:37 ` Nigel Cunningham
2004-11-24 12:59 ` Nigel Cunningham [this message]
2004-11-24 12:59 ` Suspend 2 merge: 28/51: Suspend memory pool hooks Nigel Cunningham
2004-11-25 19:34 ` Pavel Machek
2004-11-24 12:59 ` Suspend 2 merge: 29/51: Clear swapfile bdev in swapoff Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 30/51: Enable slab alloc fallback to suspend memory pool Nigel Cunningham
2004-11-25 19:36 ` Pavel Machek
2004-11-24 12:59 ` Suspend 2 merge: 31/51: Export tlb flushing Nigel Cunningham
2004-11-24 15:32 ` Martin J. Bligh
2004-11-24 21:04 ` Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 32/51: Make show task non-static Nigel Cunningham
2004-11-24 12:59 ` Suspend 2 merge: 33/51: More documentation Nigel Cunningham
2004-11-24 13:00 ` Suspend 2 merge: 34/51: Includes Nigel Cunningham
2004-11-24 13:25 ` Christoph Hellwig
2004-11-24 20:17 ` Nigel Cunningham
2004-11-24 23:19 ` Matthew Garrett
2004-11-25 2:43 ` Nigel Cunningham
2004-11-24 13:00 ` Suspend 2 merge: 35/51: Code always built in to the kernel Nigel Cunningham
2004-11-25 23:32 ` Pavel Machek
2004-11-25 23:57 ` Nigel Cunningham
2004-11-26 0:08 ` Pavel Machek
2004-11-26 0:17 ` Nigel Cunningham
2004-11-26 0:23 ` Pavel Machek
2004-11-27 2:19 ` Matthew Garrett
2004-11-28 22:39 ` Nigel Cunningham
2004-11-27 9:00 ` Jan Rychter
2004-11-27 17:22 ` Pavel Machek
2004-11-24 13:00 ` Suspend 2 merge: 36/51: Highlevel I/O routines Nigel Cunningham
2004-11-25 23:36 ` Pavel Machek
2004-11-27 1:39 ` Tomas Carnecky
2004-11-24 13:00 ` Suspend 2 merge: 37/51: Memory pool support Nigel Cunningham
2004-11-25 23:37 ` Pavel Machek
2004-11-24 13:00 ` Suspend 2 merge: 38/51: Page directory support Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 39/51: Plugins support Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 40/51: Prepare image Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 41/51: Ranges (extents) Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 42/51: Suspend.c Nigel Cunningham
2004-11-24 16:52 ` Zwane Mwaikambo
2004-11-24 21:23 ` Nigel Cunningham
2004-11-25 23:43 ` Pavel Machek
2004-11-24 13:01 ` Suspend 2 merge: 43/51: Utility functions Nigel Cunningham
2004-11-25 23:46 ` Pavel Machek
2004-11-26 0:04 ` Nigel Cunningham
2004-11-27 16:11 ` Dave Hansen
2004-11-28 21:36 ` Nigel Cunningham
2004-11-24 13:01 ` Suspend 2 merge: 44/51: Text UI plugin Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 45/51: Bootsplash support Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 46/51: LZF support Nigel Cunningham
2004-11-24 23:01 ` Bartlomiej Zolnierkiewicz
2004-11-25 2:38 ` Nigel Cunningham
2004-11-25 6:32 ` hugang
2004-11-25 6:52 ` Dmitry Torokhov
2004-11-25 7:07 ` hugang
2004-11-25 10:10 ` Christoph Hellwig
2004-11-24 13:02 ` Suspend 2 merge: 47/51: GZIP support Nigel Cunningham
2004-11-25 23:50 ` Pavel Machek
2004-11-24 13:02 ` Suspend 2 merge: 48/51: Swapwriter Nigel Cunningham
2004-11-25 23:55 ` Pavel Machek
2004-11-26 0:05 ` Nigel Cunningham
2004-11-24 13:02 ` Suspend 2 merge: 49/51: Checksumming Nigel Cunningham
2004-11-25 23:56 ` Pavel Machek
2004-11-26 0:00 ` Nigel Cunningham
2004-11-26 0:14 ` Pavel Machek
2004-11-29 9:55 ` Rob Landley
2004-11-30 0:24 ` Nigel Cunningham
2004-11-29 23:30 ` Rob Landley
2004-11-30 0:49 ` Nigel Cunningham
2004-11-30 13:07 ` Pavel Machek
2004-11-30 21:45 ` Nigel Cunningham
2004-11-30 13:02 ` Pavel Machek
2004-11-30 13:38 ` Matthew Garrett
2004-11-30 22:38 ` Pavel Machek
2004-12-02 21:31 ` Rob Landley
2004-11-24 13:02 ` Suspend 2 merge: 50/51: Device mapper support Nigel Cunningham
2004-11-25 23:58 ` Pavel Machek
2004-11-26 0:07 ` Nigel Cunningham
2004-12-02 20:40 ` Alasdair G Kergon
2004-12-02 21:04 ` Nigel Cunningham
2004-12-02 21:49 ` Alasdair G Kergon
2004-12-02 22:08 ` Nigel Cunningham
2004-12-03 17:47 ` Alasdair G Kergon
2004-12-03 19:57 ` Nigel Cunningham
2004-12-03 20:12 ` Alasdair G Kergon
2004-12-14 0:47 ` Nigel Cunningham
2004-11-24 13:03 ` Suspend 2 merge: 51/51: Notes Nigel Cunningham
2004-11-26 0:01 ` Pavel Machek
2004-11-26 0:09 ` Nigel Cunningham
2004-11-26 0:24 ` Pavel Machek
2004-11-24 13:03 ` Suspend 2 merge: 6/51 Nigel Cunningham
2004-11-24 13:28 ` Suspend 2 merge Christoph Hellwig
2004-11-24 20:46 ` Nigel Cunningham
2004-11-25 19:20 ` Pavel Machek
2004-11-25 22:34 ` Nigel Cunningham
2004-11-25 23:22 ` Pavel Machek
2004-11-25 23:46 ` Nigel Cunningham
2004-11-26 0:39 ` Pavel Machek
2004-11-26 9:08 ` Nigel Cunningham
2004-11-26 12:38 ` Pavel Machek
2004-11-26 15:54 ` Christoph Hellwig
2004-11-26 22:36 ` Pavel Machek
2004-11-28 22:35 ` Nigel Cunningham
2004-11-28 23:55 ` Pavel Machek
2004-11-29 3:20 ` Nigel Cunningham
2004-11-29 13:03 ` Pavel Machek
2004-11-30 0:24 ` Nigel Cunningham
2004-11-30 10:19 ` Pavel Machek
[not found] ` <20041126082109.GA842@hugang.soulinfo.com>
2004-11-26 13:25 ` Pavel Machek
[not found] ` <20041126043203.GA2713@hugang.soulinfo.com>
2004-11-26 9:08 ` Nigel Cunningham
2004-11-26 13:37 ` Pavel Machek
2004-11-26 13:31 ` Pavel Machek
2004-11-28 21:40 ` Nigel Cunningham
2004-11-29 9:34 ` Stefan Seyfried
2004-11-29 22:20 ` Nigel Cunningham
2004-11-29 22:34 ` Pavel Machek
2004-11-30 12:16 ` Stefan Seyfried
2004-11-30 21:16 ` Nigel Cunningham
2004-11-30 22:20 ` Pavel Machek
2004-12-01 9:27 ` Nigel Cunningham
2004-12-01 10:08 ` Pavel Machek
2004-12-01 20:39 ` Nigel Cunningham
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1101296756.5805.296.camel@desktop.cunninghams \
--to=ncunningham@linuxmail.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).