diff options
author | Minchan Kim <minchan@kernel.org> | 2013-07-03 18:01:24 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-07-03 19:07:26 -0400 |
commit | b430e9d1c6d416306d44dbf3aa3148be7af78abc (patch) | |
tree | 6227c913d4ffec2cab3149495ed5e8f72946562c /mm/page_io.c | |
parent | ffbdccf5e1facd18b54429a749667fb185c10f20 (diff) |
mm: remove compressed copy from zram in-memory
Swap subsystem does lazy swap slot free with expecting the page would be
swapped out again so we can avoid unnecessary write.
But the problem in in-memory swap(ex, zram) is that it consumes memory
space until vm_swap_full(ie, used half of all of swap device) condition
meet. It could be bad if we use multiple swap device, small in-memory
swap and big storage swap or in-memory swap alone.
This patch makes swap subsystem free swap slot as soon as swap-read is
completed and make the swapcache page dirty so the page should be
written out the swap device to reclaim it. It means we never lose it.
I tested this patch with kernel compile workload.
1. before
compile time : 9882.42
zram max wasted space by fragmentation: 13471881 byte
memory space consumed by zram: 174227456 byte
the number of slot free notify: 206684
2. after
compile time : 9653.90
zram max wasted space by fragmentation: 11805932 byte
memory space consumed by zram: 154001408 byte
the number of slot free notify: 426972
[akpm@linux-foundation.org: tweak comment text]
[artem.savkov@gmail.com: fix BUG due to non-swapcache pages in end_swap_bio_read()]
[akpm@linux-foundation.org: invert unlikely() test, augment comment, 80-col cleanup]
Signed-off-by: Dan Magenheimer <dan.magenheimer@oracle.com>
Signed-off-by: Minchan Kim <minchan@kernel.org>
Signed-off-by: Artem Savkov <artem.savkov@gmail.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Seth Jennings <sjenning@linux.vnet.ibm.com>
Cc: Nitin Gupta <ngupta@vflare.org>
Cc: Konrad Rzeszutek Wilk <konrad@darnok.org>
Cc: Shaohua Li <shli@kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
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 | } |