lkml.org 
[lkml]   [2010]   [Sep]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 17/23] Hibernation: Replace bio chain
    Date
    Replace the bio_chain concept with:
    (1) simple atomic_t recording how many pages are in flight
    (2) a wait queue for waiting for all I/O to complete
    (3) a custom completion routine that frees bio structs and pages used
    for async writes as they complete, undates the atomic_t and
    wakes any waiters.

    Signed-off-by: Nigel Cunningham <nigel@tuxonice.net>
    ---
    kernel/power/block_io.c | 77 ++++++++++++++++++++++++++++------------------
    1 files changed, 47 insertions(+), 30 deletions(-)
    diff --git a/kernel/power/block_io.c b/kernel/power/block_io.c
    index e6709db..24b6db5 100644
    --- a/kernel/power/block_io.c
    +++ b/kernel/power/block_io.c
    @@ -16,23 +16,61 @@
    #include "extents.h"
    #include "block_io.h"

    -static struct bio *bio_chain;
    -
    static char *hib_ppio_buffer;
    static int hib_ppio_buffer_posn;
    int hib_prepare_buffer(void);
    void hib_free_buffer(void);

    +static atomic_t hib_io_in_progress;
    +static DECLARE_WAIT_QUEUE_HEAD(num_in_progress_wait);
    +
    +/**
    + * hib_end_bio - bio completion function.
    + * @bio: bio that has completed.
    + * @err: Error value. Yes, like end_swap_bio_read, we ignore it.
    + *
    + * Function called by the block driver from interrupt context when I/O is
    + * completed. If we were writing the page, we want to free it and will have
    + * set bio->bi_private to the parameter we should use in telling the page
    + * allocation accounting code what the page was allocated for. If we're
    + * reading the page, it will be in the singly linked list made from
    + * page->private pointers.
    + **/
    +static void hib_end_bio(struct bio *bio, int err)
    +{
    + const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
    + struct page *page = bio->bi_io_vec[0].bv_page;
    +
    + if (!uptodate) {
    + SetPageError(page);
    + ClearPageUptodate(page);
    + printk(KERN_ALERT "I/O on swap-device (%u:%u:%Lu)\n",
    + imajor(bio->bi_bdev->bd_inode),
    + iminor(bio->bi_bdev->bd_inode),
    + (unsigned long long)bio->bi_sector);
    + } else {
    + SetPageUptodate(page);
    + }
    + unlock_page(page);
    + bio_put(bio);
    +
    + if (bio->bi_private)
    + __free_page(page);
    +
    + atomic_dec(&hib_io_in_progress);
    + wake_up(&num_in_progress_wait);
    +}
    +
    /**
    * submit - submit BIO request.
    * @rw: READ or WRITE.
    * @off physical offset of page.
    * @page: page we're reading or writing.
    - * @bio_chain: list of pending biod (for async reading)
    + * @sync: whether the i/o should be done synchronously
    *
    * Straight from the textbook - allocate and initialize the bio.
    * If we're reading, make sure the page is marked as dirty.
    - * Then submit it and, if @bio_chain == NULL, wait.
    + * Then submit it and, if @sync, wait.
    */
    static int submit(int rw, struct block_device *bdev, sector_t sector,
    struct page *page, int sync)
    @@ -43,7 +81,8 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
    bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
    bio->bi_sector = sector;
    bio->bi_bdev = bdev;
    - bio->bi_end_io = end_swap_bio_read;
    + bio->bi_private = (void *) (rw && !sync);
    + bio->bi_end_io = hib_end_bio;

    if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
    printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
    @@ -54,6 +93,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,

    lock_page(page);
    bio_get(bio);
    + atomic_inc(&hib_io_in_progress);

    if (sync) {
    submit_bio(bio_rw, bio);
    @@ -64,8 +104,6 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
    } else {
    if (rw == READ)
    get_page(page); /* These pages are freed later */
    - bio->bi_private = bio_chain;
    - bio_chain = bio;
    submit_bio(bio_rw, bio);
    }
    return 0;
    @@ -85,29 +123,8 @@ int hib_bio_write_page(pgoff_t page_off, void *addr, int sync)

    int hib_wait_on_bio_chain(void)
    {
    - struct bio *bio;
    - struct bio *next_bio;
    - int ret = 0;
    -
    - if (bio_chain == NULL)
    - return 0;
    -
    - bio = bio_chain;
    -
    - while (bio) {
    - struct page *page;
    -
    - next_bio = bio->bi_private;
    - page = bio->bi_io_vec[0].bv_page;
    - wait_on_page_locked(page);
    - if (!PageUptodate(page) || PageError(page))
    - ret = -EIO;
    - put_page(page);
    - bio_put(bio);
    - bio = next_bio;
    - }
    - bio_chain = NULL;
    - return ret;
    + wait_event(num_in_progress_wait, !atomic_read(&hib_io_in_progress));
    + return 0;
    }

    /*
    --
    1.7.0.4


    \
     
     \ /
      Last update: 2010-09-27 20:11    [from the cache]
    ©2003-2011 Jasper Spaans