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

Kirill Tkhai ktkhai at virtuozzo.com
Fri Aug 4 13:59:05 MSK 2017


On 04.08.2017 11:18, Konstantin Khorenko wrote:
> Will it work in case the host does not has swap configured at all?
> Can we implement so this tweak works even in case the host does not have a swap? (people do set up such installations)

Nope, it won't be, as it's a swap backend.
 
> -- 
> 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