]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - mm/page_io.c
mm: add support for a filesystem to activate swap files and use direct_IO for writing...
[karo-tx-linux.git] / mm / page_io.c
index 34f02923744c921fa2d990ec68f220a698049362..307a3e795290159caab708a39a3915c934cb2cf7 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/swap.h>
 #include <linux/bio.h>
 #include <linux/swapops.h>
+#include <linux/buffer_head.h>
 #include <linux/writeback.h>
 #include <linux/frontswap.h>
 #include <asm/pgtable.h>
@@ -94,6 +95,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
 {
        struct bio *bio;
        int ret = 0, rw = WRITE;
+       struct swap_info_struct *sis = page_swap_info(page);
 
        if (try_to_free_swap(page)) {
                unlock_page(page);
@@ -105,6 +107,32 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
                end_page_writeback(page);
                goto out;
        }
+
+       if (sis->flags & SWP_FILE) {
+               struct kiocb kiocb;
+               struct file *swap_file = sis->swap_file;
+               struct address_space *mapping = swap_file->f_mapping;
+               struct iovec iov = {
+                       .iov_base = page_address(page),
+                       .iov_len  = PAGE_SIZE,
+               };
+
+               init_sync_kiocb(&kiocb, swap_file);
+               kiocb.ki_pos = page_file_offset(page);
+               kiocb.ki_left = PAGE_SIZE;
+               kiocb.ki_nbytes = PAGE_SIZE;
+
+               unlock_page(page);
+               ret = mapping->a_ops->direct_IO(KERNEL_WRITE,
+                                               &kiocb, &iov,
+                                               kiocb.ki_pos, 1);
+               if (ret == PAGE_SIZE) {
+                       count_vm_event(PSWPOUT);
+                       ret = 0;
+               }
+               return ret;
+       }
+
        bio = get_swap_bio(GFP_NOIO, page, end_swap_bio_write);
        if (bio == NULL) {
                set_page_dirty(page);
@@ -126,6 +154,7 @@ int swap_readpage(struct page *page)
 {
        struct bio *bio;
        int ret = 0;
+       struct swap_info_struct *sis = page_swap_info(page);
 
        VM_BUG_ON(!PageLocked(page));
        VM_BUG_ON(PageUptodate(page));
@@ -134,6 +163,17 @@ int swap_readpage(struct page *page)
                unlock_page(page);
                goto out;
        }
+
+       if (sis->flags & SWP_FILE) {
+               struct file *swap_file = sis->swap_file;
+               struct address_space *mapping = swap_file->f_mapping;
+
+               ret = mapping->a_ops->readpage(swap_file, page);
+               if (!ret)
+                       count_vm_event(PSWPIN);
+               return ret;
+       }
+
        bio = get_swap_bio(GFP_KERNEL, page, end_swap_bio_read);
        if (bio == NULL) {
                unlock_page(page);
@@ -145,3 +185,15 @@ int swap_readpage(struct page *page)
 out:
        return ret;
 }
+
+int swap_set_page_dirty(struct page *page)
+{
+       struct swap_info_struct *sis = page_swap_info(page);
+
+       if (sis->flags & SWP_FILE) {
+               struct address_space *mapping = sis->swap_file->f_mapping;
+               return mapping->a_ops->set_page_dirty(page);
+       } else {
+               return __set_page_dirty_no_writeback(page);
+       }
+}