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: 244+ 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-26 0:04 ` Nigel Cunningham
2004-11-27 16:11 ` Dave Hansen
2004-11-27 16:11 ` Dave Hansen
2004-11-28 21:36 ` Nigel Cunningham
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] ` <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
[not found] ` <20041126082109.GA842@hugang.soulinfo.com>
2004-11-26 13:25 ` 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.