Add the rt linux 4.1.3-rt3 as base
[kvmfornfv.git] / kernel / kernel / power / block_io.c
diff --git a/kernel/kernel/power/block_io.c b/kernel/kernel/power/block_io.c
new file mode 100644 (file)
index 0000000..9a58bc2
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * This file provides functions for block I/O operations on swap/file.
+ *
+ * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz>
+ * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
+ *
+ * This file is released under the GPLv2.
+ */
+
+#include <linux/bio.h>
+#include <linux/kernel.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+
+#include "power.h"
+
+/**
+ *     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)
+ *
+ *     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.
+ */
+static int submit(int rw, struct block_device *bdev, sector_t sector,
+               struct page *page, struct bio **bio_chain)
+{
+       const int bio_rw = rw | REQ_SYNC;
+       struct bio *bio;
+
+       bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
+       bio->bi_iter.bi_sector = sector;
+       bio->bi_bdev = bdev;
+       bio->bi_end_io = end_swap_bio_read;
+
+       if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE) {
+               printk(KERN_ERR "PM: Adding page to bio failed at %llu\n",
+                       (unsigned long long)sector);
+               bio_put(bio);
+               return -EFAULT;
+       }
+
+       lock_page(page);
+       bio_get(bio);
+
+       if (bio_chain == NULL) {
+               submit_bio(bio_rw, bio);
+               wait_on_page_locked(page);
+               if (rw == READ)
+                       bio_set_pages_dirty(bio);
+               bio_put(bio);
+       } 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;
+}
+
+int hib_bio_read_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+{
+       return submit(READ, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
+                       virt_to_page(addr), bio_chain);
+}
+
+int hib_bio_write_page(pgoff_t page_off, void *addr, struct bio **bio_chain)
+{
+       return submit(WRITE, hib_resume_bdev, page_off * (PAGE_SIZE >> 9),
+                       virt_to_page(addr), bio_chain);
+}
+
+int hib_wait_on_bio_chain(struct bio **bio_chain)
+{
+       struct bio *bio;
+       struct bio *next_bio;
+       int ret = 0;
+
+       if (bio_chain == NULL)
+               return 0;
+
+       bio = *bio_chain;
+       if (bio == NULL)
+               return 0;
+       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;
+}