|
@@ -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);
|
|
|
+ }
|
|
|
+}
|