#include <linux/mempolicy.h>
#include <linux/mempool.h>
#include <crypto/acompress.h>
+#include <crypto/scatterwalk.h>
#include <linux/zswap.h>
#include <linux/mm_types.h>
#include <linux/page-flags.h>
static bool zswap_decompress(struct zswap_entry *entry, struct folio *folio)
{
struct zswap_pool *pool = entry->pool;
- struct scatterlist input, output;
+ struct scatterlist input[2]; /* zsmalloc returns an SG list 1-2 entries */
+ struct scatterlist output;
struct crypto_acomp_ctx *acomp_ctx;
- int decomp_ret = 0, dlen = PAGE_SIZE;
- u8 *src, *obj;
+ int ret = 0, dlen;
acomp_ctx = acomp_ctx_get_cpu_lock(pool);
- obj = zs_obj_read_begin(pool->zs_pool, entry->handle, entry->length,
- acomp_ctx->buffer);
+ zs_obj_read_sg_begin(pool->zs_pool, entry->handle, input, entry->length);
/* zswap entries of length PAGE_SIZE are not compressed. */
if (entry->length == PAGE_SIZE) {
- memcpy_to_folio(folio, 0, obj, entry->length);
- goto read_done;
- }
-
- /*
- * zs_obj_read_begin() might return a kmap address of highmem when
- * acomp_ctx->buffer is not used. However, sg_init_one() does not
- * handle highmem addresses, so copy the object to acomp_ctx->buffer.
- */
- if (virt_addr_valid(obj)) {
- src = obj;
+ WARN_ON_ONCE(input->length != PAGE_SIZE);
+ memcpy_from_sglist(kmap_local_folio(folio, 0), input, 0, PAGE_SIZE);
+ dlen = PAGE_SIZE;
} else {
- WARN_ON_ONCE(obj == acomp_ctx->buffer);
- memcpy(acomp_ctx->buffer, obj, entry->length);
- src = acomp_ctx->buffer;
+ sg_init_table(&output, 1);
+ sg_set_folio(&output, folio, PAGE_SIZE, 0);
+ acomp_request_set_params(acomp_ctx->req, input, &output,
+ entry->length, PAGE_SIZE);
+ ret = crypto_acomp_decompress(acomp_ctx->req);
+ ret = crypto_wait_req(ret, &acomp_ctx->wait);
+ dlen = acomp_ctx->req->dlen;
}
- sg_init_one(&input, src, entry->length);
- sg_init_table(&output, 1);
- sg_set_folio(&output, folio, PAGE_SIZE, 0);
- acomp_request_set_params(acomp_ctx->req, &input, &output, entry->length, PAGE_SIZE);
- decomp_ret = crypto_wait_req(crypto_acomp_decompress(acomp_ctx->req), &acomp_ctx->wait);
- dlen = acomp_ctx->req->dlen;
-
-read_done:
- zs_obj_read_end(pool->zs_pool, entry->handle, entry->length, obj);
+ zs_obj_read_sg_end(pool->zs_pool, entry->handle);
acomp_ctx_put_unlock(acomp_ctx);
- if (!decomp_ret && dlen == PAGE_SIZE)
+ if (!ret && dlen == PAGE_SIZE)
return true;
zswap_decompress_fail++;
pr_alert_ratelimited("Decompression error from zswap (%d:%lu %s %u->%d)\n",
swp_type(entry->swpentry),
swp_offset(entry->swpentry),
- entry->pool->tfm_name, entry->length, dlen);
+ entry->pool->tfm_name,
+ entry->length, dlen);
return false;
}