On 03/15/2013 10:34 AM, Wanpeng Li wrote:
> Compression of zero-filled pages can unneccessarily cause internal
> fragmentation, and thus waste memory. This special case can be
> optimized.
> 
> This patch captures zero-filled pages, and marks their corresponding
> zcache backing page entry as zero-filled. Whenever such zero-filled
> page is retrieved, we fill the page frame with zero.
> 
> Acked-by: Dan Magenheimer <dan.magenhei...@oracle.com>
> Signed-off-by: Wanpeng Li <liw...@linux.vnet.ibm.com>
> ---
>  drivers/staging/zcache/zcache-main.c |   81 
> +++++++++++++++++++++++++++++++---
>  1 files changed, 75 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/staging/zcache/zcache-main.c 
> b/drivers/staging/zcache/zcache-main.c
> index d73dd4b..6c35c7d 100644
> --- a/drivers/staging/zcache/zcache-main.c
> +++ b/drivers/staging/zcache/zcache-main.c
> @@ -59,6 +59,12 @@ static inline void frontswap_tmem_exclusive_gets(bool b)
>  }
>  #endif
>  
> +/*
> + * mark pampd to special value in order that later
> + * retrieve will identify zero-filled pages
> + */
> +#define ZERO_FILLED 0x2
> +
>  /* enable (or fix code) when Seth's patches are accepted upstream */
>  #define zcache_writeback_enabled 0
>  
> @@ -543,7 +549,23 @@ static void *zcache_pampd_eph_create(char *data, size_t 
> size, bool raw,
>  {
>       void *pampd = NULL, *cdata = data;
>       unsigned clen = size;
> +     bool zero_filled = false;
>       struct page *page = (struct page *)(data), *newpage;
> +     char *user_mem;
> +
> +     user_mem = kmap_atomic(page);
> +
> +     /*
> +      * Compressing zero-filled pages will waste memory and introduce
> +      * serious fragmentation, skip it to avoid overhead
> +      */
> +     if (page_is_zero_filled(user_mem)) {
> +             kunmap_atomic(user_mem);
> +             clen = 0;
> +             zero_filled = true;
> +             goto got_pampd;
> +     }
> +     kunmap_atomic(user_mem);
>  
>       if (!raw) {
>               zcache_compress(page, &cdata, &clen);
> @@ -592,6 +614,8 @@ got_pampd:
>               zcache_eph_zpages_max = zcache_eph_zpages;
>       if (ramster_enabled && raw)
>               ramster_count_foreign_pages(true, 1);
> +     if (zero_filled)
> +             pampd = (void *)ZERO_FILLED;
>  out:
>       return pampd;
>  }
> @@ -601,14 +625,31 @@ static void *zcache_pampd_pers_create(char *data, 
> size_t size, bool raw,
>  {
>       void *pampd = NULL, *cdata = data;
>       unsigned clen = size;
> +     bool zero_filled = false;
>       struct page *page = (struct page *)(data), *newpage;
>       unsigned long zbud_mean_zsize;
>       unsigned long curr_pers_zpages, total_zsize;
> +     char *user_mem;
>  
>       if (data == NULL) {
>               BUG_ON(!ramster_enabled);
>               goto create_pampd;
>       }
> +
> +     user_mem = kmap_atomic(page);
> +
> +     /*
> +      * Compressing zero-filled pages will waste memory and introduce
> +      * serious fragmentation, skip it to avoid overhead
> +      */
> +     if (page_is_zero_filled(page)) {
> +             kunmap_atomic(user_mem);
> +             clen = 0;
> +             zero_filled = true;
> +             goto got_pampd;
> +     }
> +     kunmap_atomic(user_mem);
> +

Maybe we can add a function for this code? It seems a bit duplicated.

>       curr_pers_zpages = zcache_pers_zpages;
>  /* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */
>       if (!raw)
> @@ -674,6 +715,8 @@ got_pampd:
>               zcache_pers_zbytes_max = zcache_pers_zbytes;
>       if (ramster_enabled && raw)
>               ramster_count_foreign_pages(false, 1);
> +     if (zero_filled)
> +             pampd = (void *)ZERO_FILLED;
>  out:
>       return pampd;
>  }
> @@ -735,7 +778,8 @@ out:
>   */
>  void zcache_pampd_create_finish(void *pampd, bool eph)
>  {
> -     zbud_create_finish((struct zbudref *)pampd, eph);
> +     if (pampd != (void *)ZERO_FILLED)
> +             zbud_create_finish((struct zbudref *)pampd, eph);
>  }
>  
>  /*
> @@ -780,6 +824,14 @@ static int zcache_pampd_get_data(char *data, size_t 
> *sizep, bool raw,
>       BUG_ON(preemptible());
>       BUG_ON(eph);    /* fix later if shared pools get implemented */
>       BUG_ON(pampd_is_remote(pampd));
> +
> +     if (pampd == (void *)ZERO_FILLED) {
> +             handle_zero_filled_page(data);
> +             if (!raw)
> +                     *sizep = PAGE_SIZE;
> +             return 0;
> +     }
> +
>       if (raw)
>               ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
>                                               sizep, eph);
> @@ -801,12 +853,21 @@ static int zcache_pampd_get_data_and_free(char *data, 
> size_t *sizep, bool raw,
>                                       struct tmem_oid *oid, uint32_t index)
>  {
>       int ret;
> -     bool eph = !is_persistent(pool);
> +     bool eph = !is_persistent(pool), zero_filled = false;
>       struct page *page = NULL;
>       unsigned int zsize, zpages;
>  
>       BUG_ON(preemptible());
>       BUG_ON(pampd_is_remote(pampd));
> +
> +     if (pampd == (void *)ZERO_FILLED) {
> +             handle_zero_filled_page(data);
> +             zero_filled = true;
> +             if (!raw)
> +                     *sizep = PAGE_SIZE;
> +             goto zero_fill;
> +     }
> +
>       if (raw)
>               ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd,
>                                               sizep, eph);
> @@ -818,6 +879,7 @@ static int zcache_pampd_get_data_and_free(char *data, 
> size_t *sizep, bool raw,
>       }
>       page = zbud_free_and_delist((struct zbudref *)pampd, eph,
>                                       &zsize, &zpages);
> +zero_fill:
>       if (eph) {
>               if (page)
>                       zcache_eph_pageframes =
> @@ -837,7 +899,7 @@ static int zcache_pampd_get_data_and_free(char *data, 
> size_t *sizep, bool raw,
>       }
>       if (!is_local_client(pool->client))
>               ramster_count_foreign_pages(eph, -1);
> -     if (page)
> +     if (page && !zero_filled)
>               zcache_free_page(page);
>       return ret;
>  }
> @@ -851,16 +913,23 @@ static void zcache_pampd_free(void *pampd, struct 
> tmem_pool *pool,
>  {
>       struct page *page = NULL;
>       unsigned int zsize, zpages;
> +     bool zero_filled = false;
>  
>       BUG_ON(preemptible());
> -     if (pampd_is_remote(pampd)) {
> +
> +     if (pampd == (void *)ZERO_FILLED)
> +             zero_filled = true;
> +
> +     if (pampd_is_remote(pampd) && !zero_filled) {
> +
>               BUG_ON(!ramster_enabled);
>               pampd = ramster_pampd_free(pampd, pool, oid, index, acct);
>               if (pampd == NULL)
>                       return;
>       }
>       if (is_ephemeral(pool)) {
> -             page = zbud_free_and_delist((struct zbudref *)pampd,
> +             if (!zero_filled)
> +                     page = zbud_free_and_delist((struct zbudref *)pampd,
>                                               true, &zsize, &zpages);
>               if (page)
>                       zcache_eph_pageframes =
> @@ -883,7 +952,7 @@ static void zcache_pampd_free(void *pampd, struct 
> tmem_pool *pool,
>       }
>       if (!is_local_client(pool->client))
>               ramster_count_foreign_pages(is_ephemeral(pool), -1);
> -     if (page)
> +     if (page && !zero_filled)
>               zcache_free_page(page);
>  }
>  
> 

-- 
Regards,
-Bob
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to