Commit 9ae77198 authored by Gao Xiang's avatar Gao Xiang
Browse files

erofs: tidy up z_erofs_lz4_handle_overlap()



 - Add some useful comments to explain inplace I/Os and decompression;

 - Rearrange the code to get rid of one unnecessary goto.

Reviewed-by: default avatarChao Yu <chao@kernel.org>
Signed-off-by: default avatarGao Xiang <hsiangkao@linux.alibaba.com>
parent d53cd891
Loading
Loading
Loading
Loading
+46 −39
Original line number Diff line number Diff line
@@ -105,30 +105,20 @@ static int z_erofs_lz4_prepare_dstpages(struct z_erofs_decompress_req *rq,
	return kaddr ? 1 : 0;
}

static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
static void *z_erofs_lz4_handle_overlap(const struct z_erofs_decompress_req *rq,
			void *inpage, void *out, unsigned int *inputmargin,
			int *maptype, bool may_inplace)
{
	unsigned int oend, omargin, total, i;
	unsigned int oend, omargin, cnt, i;
	struct page **in;
	void *src, *tmp;

	if (rq->inplace_io) {
		oend = rq->pageofs_out + rq->outputsize;
		omargin = PAGE_ALIGN(oend) - oend;
		if (rq->partial_decoding || !may_inplace ||
		    omargin < LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize))
			goto docopy;

		for (i = 0; i < rq->inpages; ++i)
			if (rq->out[rq->outpages - rq->inpages + i] !=
			    rq->in[i])
				goto docopy;
		kunmap_local(inpage);
		*maptype = 3;
		return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
	}
	void *src;

	/*
	 * If in-place I/O isn't used, for example, the bounce compressed cache
	 * can hold data for incomplete read requests. Just map the compressed
	 * buffer as well and decompress directly.
	 */
	if (!rq->inplace_io) {
		if (rq->inpages <= 1) {
			*maptype = 0;
			return inpage;
@@ -139,10 +129,34 @@ static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
			return ERR_PTR(-ENOMEM);
		*maptype = 1;
		return src;

docopy:
	/* Or copy compressed data which can be overlapped to per-CPU buffer */
	in = rq->in;
	}
	/*
	 * Then, deal with in-place I/Os. The reasons why in-place I/O is useful
	 * are: (1) It minimizes memory footprint during the I/O submission,
	 * which is useful for slow storage (including network devices and
	 * low-end HDDs/eMMCs) but with a lot inflight I/Os; (2) If in-place
	 * decompression can also be applied, it will reuse the unique buffer so
	 * that no extra CPU D-cache is polluted with temporary compressed data
	 * for extreme performance.
	 */
	oend = rq->pageofs_out + rq->outputsize;
	omargin = PAGE_ALIGN(oend) - oend;
	if (!rq->partial_decoding && may_inplace &&
	    omargin >= LZ4_DECOMPRESS_INPLACE_MARGIN(rq->inputsize)) {
		for (i = 0; i < rq->inpages; ++i)
			if (rq->out[rq->outpages - rq->inpages + i] !=
			    rq->in[i])
				break;
		if (i >= rq->inpages) {
			kunmap_local(inpage);
			*maptype = 3;
			return out + ((rq->outpages - rq->inpages) << PAGE_SHIFT);
		}
	}
	/*
	 * If in-place decompression can't be applied, copy compressed data that
	 * may potentially overlap during decompression to a per-CPU buffer.
	 */
	src = z_erofs_get_gbuf(rq->inpages);
	if (!src) {
		DBG_BUGON(1);
@@ -150,20 +164,13 @@ static void *z_erofs_lz4_handle_overlap(struct z_erofs_decompress_req *rq,
		return ERR_PTR(-EFAULT);
	}

	tmp = src;
	total = rq->inputsize;
	while (total) {
		unsigned int page_copycnt =
			min_t(unsigned int, total, PAGE_SIZE - *inputmargin);

	for (i = 0, in = rq->in; i < rq->inputsize; i += cnt, ++in) {
		cnt = min_t(u32, rq->inputsize - i, PAGE_SIZE - *inputmargin);
		if (!inpage)
			inpage = kmap_local_page(*in);
		memcpy(tmp, inpage + *inputmargin, page_copycnt);
		memcpy(src + i, inpage + *inputmargin, cnt);
		kunmap_local(inpage);
		inpage = NULL;
		tmp += page_copycnt;
		total -= page_copycnt;
		++in;
		*inputmargin = 0;
	}
	*maptype = 2;