diff options
Diffstat (limited to 'mm/page_io.c')
-rw-r--r-- | mm/page_io.c | 50 |
1 files changed, 48 insertions, 2 deletions
diff --git a/mm/page_io.c b/mm/page_io.c index a8a3ef45fed7..ba05b64e5d8d 100644 --- a/mm/page_io.c +++ b/mm/page_io.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/writeback.h> | 21 | #include <linux/writeback.h> |
22 | #include <linux/frontswap.h> | 22 | #include <linux/frontswap.h> |
23 | #include <linux/aio.h> | 23 | #include <linux/aio.h> |
24 | #include <linux/blkdev.h> | ||
24 | #include <asm/pgtable.h> | 25 | #include <asm/pgtable.h> |
25 | 26 | ||
26 | static struct bio *get_swap_bio(gfp_t gfp_flags, | 27 | static struct bio *get_swap_bio(gfp_t gfp_flags, |
@@ -80,9 +81,54 @@ void end_swap_bio_read(struct bio *bio, int err) | |||
80 | imajor(bio->bi_bdev->bd_inode), | 81 | imajor(bio->bi_bdev->bd_inode), |
81 | iminor(bio->bi_bdev->bd_inode), | 82 | iminor(bio->bi_bdev->bd_inode), |
82 | (unsigned long long)bio->bi_sector); | 83 | (unsigned long long)bio->bi_sector); |
83 | } else { | 84 | goto out; |
84 | SetPageUptodate(page); | ||
85 | } | 85 | } |
86 | |||
87 | SetPageUptodate(page); | ||
88 | |||
89 | /* | ||
90 | * There is no guarantee that the page is in swap cache - the software | ||
91 | * suspend code (at least) uses end_swap_bio_read() against a non- | ||
92 | * swapcache page. So we must check PG_swapcache before proceeding with | ||
93 | * this optimization. | ||
94 | */ | ||
95 | if (likely(PageSwapCache(page))) { | ||
96 | struct swap_info_struct *sis; | ||
97 | |||
98 | sis = page_swap_info(page); | ||
99 | if (sis->flags & SWP_BLKDEV) { | ||
100 | /* | ||
101 | * The swap subsystem performs lazy swap slot freeing, | ||
102 | * expecting that the page will be swapped out again. | ||
103 | * So we can avoid an unnecessary write if the page | ||
104 | * isn't redirtied. | ||
105 | * This is good for real swap storage because we can | ||
106 | * reduce unnecessary I/O and enhance wear-leveling | ||
107 | * if an SSD is used as the as swap device. | ||
108 | * But if in-memory swap device (eg zram) is used, | ||
109 | * this causes a duplicated copy between uncompressed | ||
110 | * data in VM-owned memory and compressed data in | ||
111 | * zram-owned memory. So let's free zram-owned memory | ||
112 | * and make the VM-owned decompressed page *dirty*, | ||
113 | * so the page should be swapped out somewhere again if | ||
114 | * we again wish to reclaim it. | ||
115 | */ | ||
116 | struct gendisk *disk = sis->bdev->bd_disk; | ||
117 | if (disk->fops->swap_slot_free_notify) { | ||
118 | swp_entry_t entry; | ||
119 | unsigned long offset; | ||
120 | |||
121 | entry.val = page_private(page); | ||
122 | offset = swp_offset(entry); | ||
123 | |||
124 | SetPageDirty(page); | ||
125 | disk->fops->swap_slot_free_notify(sis->bdev, | ||
126 | offset); | ||
127 | } | ||
128 | } | ||
129 | } | ||
130 | |||
131 | out: | ||
86 | unlock_page(page); | 132 | unlock_page(page); |
87 | bio_put(bio); | 133 | bio_put(bio); |
88 | } | 134 | } |