[Devel] [PATCH rh7] tswap: Add support for zero-filled pages

Konstantin Khorenko khorenko at virtuozzo.com
Thu Aug 31 14:48:45 MSK 2017


Andrey, please review the patch.

--
Best regards,

Konstantin Khorenko,
Virtuozzo Linux Kernel Team

On 08/03/2017 12:54 PM, Kirill Tkhai wrote:
> This patch makes tswap to do not allocate a new page,
> if swapped page is zero-filled, and to use ZERO_PAGE()
> pointer to decode it instead.
>
> The same optimization is made in zram, and it may help
> VMs to reduce memory usage in some way.
>
> Signed-off-by: Kirill Tkhai <ktkhai at virtuozzo.com>
> ---
>  mm/tswap.c |   65 +++++++++++++++++++++++++++++++++++++++++++++++-------------
>  1 file changed, 51 insertions(+), 14 deletions(-)
>
> diff --git a/mm/tswap.c b/mm/tswap.c
> index 15f5adc2dc9..6a3cb917059 100644
> --- a/mm/tswap.c
> +++ b/mm/tswap.c
> @@ -54,16 +54,20 @@ static void tswap_lru_add(struct page *page)
>  {
>  	struct tswap_lru *lru = &tswap_lru_node[page_to_nid(page)];
>
> -	list_add_tail(&page->lru, &lru->list);
> -	lru->nr_items++;
> +	if (page != ZERO_PAGE(0)) {
> +		list_add_tail(&page->lru, &lru->list);
> +		lru->nr_items++;
> +	}
>  }
>
>  static void tswap_lru_del(struct page *page)
>  {
>  	struct tswap_lru *lru = &tswap_lru_node[page_to_nid(page)];
>
> -	list_del(&page->lru);
> -	lru->nr_items--;
> +	if (page != ZERO_PAGE(0)) {
> +		list_del(&page->lru);
> +		lru->nr_items--;
> +	}
>  }
>
>  static struct page *tswap_lookup_page(swp_entry_t entry)
> @@ -73,7 +77,7 @@ static struct page *tswap_lookup_page(swp_entry_t entry)
>  	spin_lock(&tswap_lock);
>  	page = radix_tree_lookup(&tswap_page_tree, entry.val);
>  	spin_unlock(&tswap_lock);
> -	BUG_ON(page && page_private(page) != entry.val);
> +	BUG_ON(page && page != ZERO_PAGE(0) && page_private(page) != entry.val);
>  	return page;
>  }
>
> @@ -85,7 +89,8 @@ static int tswap_insert_page(swp_entry_t entry, struct page *page)
>  	if (err)
>  		return err;
>
> -	set_page_private(page, entry.val);
> +	if (page != ZERO_PAGE(0))
> +		set_page_private(page, entry.val);
>  	spin_lock(&tswap_lock);
>  	err = radix_tree_insert(&tswap_page_tree, entry.val, page);
>  	if (!err) {
> @@ -111,7 +116,7 @@ static struct page *tswap_delete_page(swp_entry_t entry, struct page *expected)
>  	spin_unlock(&tswap_lock);
>  	if (page) {
>  		BUG_ON(expected && page != expected);
> -		BUG_ON(page_private(page) != entry.val);
> +		BUG_ON(page_private(page) != entry.val && page != ZERO_PAGE(0));
>  	}
>  	return page;
>  }
> @@ -274,26 +279,57 @@ static void tswap_frontswap_init(unsigned type)
>  	 */
>  }
>
> +static bool is_zero_filled_page(struct page *page)
> +{
> +	bool zero_filled = true;
> +	unsigned long *v;
> +	int i;
> +
> +	v = kmap_atomic(page);
> +	for (i = 0; i < PAGE_SIZE / sizeof(*v); i++) {
> +		if (v[i] != 0) {
> +			zero_filled = false;
> +			break;
> +		}
> +	}
> +	kunmap_atomic(v);
> +	return zero_filled;
> +}
> +
>  static int tswap_frontswap_store(unsigned type, pgoff_t offset,
>  				 struct page *page)
>  {
>  	swp_entry_t entry = swp_entry(type, offset);
> +	int zero_filled = -1, err = 0;
>  	struct page *cache_page;
> -	int err = 0;
>
>  	if (!tswap_active)
>  		return -1;
>
>  	cache_page = tswap_lookup_page(entry);
> -	if (cache_page)
> -		goto copy;
> +	if (cache_page) {
> +		zero_filled = is_zero_filled_page(page);
> +		/* If type of page has not changed, just reuse it */
> +		if (zero_filled == (cache_page == ZERO_PAGE(0)))
> +			goto copy;
> +		tswap_delete_page(entry, NULL);
> +		put_page(cache_page);
> +	}
>
>  	if (!(current->flags & PF_MEMCG_RECLAIM))
>  		return -1;
>
> -	cache_page = alloc_page(TSWAP_GFP_MASK | __GFP_HIGHMEM);
> -	if (!cache_page)
> -		return -1;
> +	if (zero_filled == -1)
> +		zero_filled = is_zero_filled_page(page);
> +
> +	if (!zero_filled) {
> +		cache_page = alloc_page(TSWAP_GFP_MASK | __GFP_HIGHMEM);
> +		if (!cache_page)
> +			return -1;
> +	} else {
> +		cache_page = ZERO_PAGE(0);
> +		get_page(cache_page);
> +	}
>
>  	err = tswap_insert_page(entry, cache_page);
>  	if (err) {
> @@ -306,7 +342,8 @@ static int tswap_frontswap_store(unsigned type, pgoff_t offset,
>  		return -1;
>  	}
>  copy:
> -	copy_highpage(cache_page, page);
> +	if (cache_page != ZERO_PAGE(0))
> +		copy_highpage(cache_page, page);
>  	return 0;
>  }
>
>
> .
>


More information about the Devel mailing list