18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2018 HUAWEI, Inc.
48c2ecf20Sopenharmony_ci *             https://www.huawei.com/
58c2ecf20Sopenharmony_ci * Created by Gao Xiang <gaoxiang25@huawei.com>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#ifndef __EROFS_FS_ZPVEC_H
88c2ecf20Sopenharmony_ci#define __EROFS_FS_ZPVEC_H
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include "tagptr.h"
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci/* page type in pagevec for decompress subsystem */
138c2ecf20Sopenharmony_cienum z_erofs_page_type {
148c2ecf20Sopenharmony_ci	/* including Z_EROFS_VLE_PAGE_TAIL_EXCLUSIVE */
158c2ecf20Sopenharmony_ci	Z_EROFS_PAGE_TYPE_EXCLUSIVE,
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci	Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED,
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	Z_EROFS_VLE_PAGE_TYPE_HEAD,
208c2ecf20Sopenharmony_ci	Z_EROFS_VLE_PAGE_TYPE_MAX
218c2ecf20Sopenharmony_ci};
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciextern void __compiletime_error("Z_EROFS_PAGE_TYPE_EXCLUSIVE != 0")
248c2ecf20Sopenharmony_ci	__bad_page_type_exclusive(void);
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_ci/* pagevec tagged pointer */
278c2ecf20Sopenharmony_citypedef tagptr2_t	erofs_vtptr_t;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* pagevec collector */
308c2ecf20Sopenharmony_cistruct z_erofs_pagevec_ctor {
318c2ecf20Sopenharmony_ci	struct page *curr, *next;
328c2ecf20Sopenharmony_ci	erofs_vtptr_t *pages;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	unsigned int nr, index;
358c2ecf20Sopenharmony_ci};
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_cistatic inline void z_erofs_pagevec_ctor_exit(struct z_erofs_pagevec_ctor *ctor,
388c2ecf20Sopenharmony_ci					     bool atomic)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	if (!ctor->curr)
418c2ecf20Sopenharmony_ci		return;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	if (atomic)
448c2ecf20Sopenharmony_ci		kunmap_atomic(ctor->pages);
458c2ecf20Sopenharmony_ci	else
468c2ecf20Sopenharmony_ci		kunmap(ctor->curr);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic inline struct page *
508c2ecf20Sopenharmony_ciz_erofs_pagevec_ctor_next_page(struct z_erofs_pagevec_ctor *ctor,
518c2ecf20Sopenharmony_ci			       unsigned int nr)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	unsigned int index;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	/* keep away from occupied pages */
568c2ecf20Sopenharmony_ci	if (ctor->next)
578c2ecf20Sopenharmony_ci		return ctor->next;
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci	for (index = 0; index < nr; ++index) {
608c2ecf20Sopenharmony_ci		const erofs_vtptr_t t = ctor->pages[index];
618c2ecf20Sopenharmony_ci		const unsigned int tags = tagptr_unfold_tags(t);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		if (tags == Z_EROFS_PAGE_TYPE_EXCLUSIVE)
648c2ecf20Sopenharmony_ci			return tagptr_unfold_ptr(t);
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci	DBG_BUGON(nr >= ctor->nr);
678c2ecf20Sopenharmony_ci	return NULL;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic inline void
718c2ecf20Sopenharmony_ciz_erofs_pagevec_ctor_pagedown(struct z_erofs_pagevec_ctor *ctor,
728c2ecf20Sopenharmony_ci			      bool atomic)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct page *next = z_erofs_pagevec_ctor_next_page(ctor, ctor->nr);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	z_erofs_pagevec_ctor_exit(ctor, atomic);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	ctor->curr = next;
798c2ecf20Sopenharmony_ci	ctor->next = NULL;
808c2ecf20Sopenharmony_ci	ctor->pages = atomic ?
818c2ecf20Sopenharmony_ci		kmap_atomic(ctor->curr) : kmap(ctor->curr);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ctor->nr = PAGE_SIZE / sizeof(struct page *);
848c2ecf20Sopenharmony_ci	ctor->index = 0;
858c2ecf20Sopenharmony_ci}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_cistatic inline void z_erofs_pagevec_ctor_init(struct z_erofs_pagevec_ctor *ctor,
888c2ecf20Sopenharmony_ci					     unsigned int nr,
898c2ecf20Sopenharmony_ci					     erofs_vtptr_t *pages,
908c2ecf20Sopenharmony_ci					     unsigned int i)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	ctor->nr = nr;
938c2ecf20Sopenharmony_ci	ctor->curr = ctor->next = NULL;
948c2ecf20Sopenharmony_ci	ctor->pages = pages;
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci	if (i >= nr) {
978c2ecf20Sopenharmony_ci		i -= nr;
988c2ecf20Sopenharmony_ci		z_erofs_pagevec_ctor_pagedown(ctor, false);
998c2ecf20Sopenharmony_ci		while (i > ctor->nr) {
1008c2ecf20Sopenharmony_ci			i -= ctor->nr;
1018c2ecf20Sopenharmony_ci			z_erofs_pagevec_ctor_pagedown(ctor, false);
1028c2ecf20Sopenharmony_ci		}
1038c2ecf20Sopenharmony_ci	}
1048c2ecf20Sopenharmony_ci	ctor->next = z_erofs_pagevec_ctor_next_page(ctor, i);
1058c2ecf20Sopenharmony_ci	ctor->index = i;
1068c2ecf20Sopenharmony_ci}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_cistatic inline bool z_erofs_pagevec_enqueue(struct z_erofs_pagevec_ctor *ctor,
1098c2ecf20Sopenharmony_ci					   struct page *page,
1108c2ecf20Sopenharmony_ci					   enum z_erofs_page_type type,
1118c2ecf20Sopenharmony_ci					   bool pvec_safereuse)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	if (!ctor->next) {
1148c2ecf20Sopenharmony_ci		/* some pages cannot be reused as pvec safely without I/O */
1158c2ecf20Sopenharmony_ci		if (type == Z_EROFS_PAGE_TYPE_EXCLUSIVE && !pvec_safereuse)
1168c2ecf20Sopenharmony_ci			type = Z_EROFS_VLE_PAGE_TYPE_TAIL_SHARED;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci		if (type != Z_EROFS_PAGE_TYPE_EXCLUSIVE &&
1198c2ecf20Sopenharmony_ci		    ctor->index + 1 == ctor->nr)
1208c2ecf20Sopenharmony_ci			return false;
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	if (ctor->index >= ctor->nr)
1248c2ecf20Sopenharmony_ci		z_erofs_pagevec_ctor_pagedown(ctor, false);
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	/* exclusive page type must be 0 */
1278c2ecf20Sopenharmony_ci	if (Z_EROFS_PAGE_TYPE_EXCLUSIVE != (uintptr_t)NULL)
1288c2ecf20Sopenharmony_ci		__bad_page_type_exclusive();
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	/* should remind that collector->next never equal to 1, 2 */
1318c2ecf20Sopenharmony_ci	if (type == (uintptr_t)ctor->next) {
1328c2ecf20Sopenharmony_ci		ctor->next = page;
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci	ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, page, type);
1358c2ecf20Sopenharmony_ci	return true;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic inline struct page *
1398c2ecf20Sopenharmony_ciz_erofs_pagevec_dequeue(struct z_erofs_pagevec_ctor *ctor,
1408c2ecf20Sopenharmony_ci			enum z_erofs_page_type *type)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	erofs_vtptr_t t;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	if (ctor->index >= ctor->nr) {
1458c2ecf20Sopenharmony_ci		DBG_BUGON(!ctor->next);
1468c2ecf20Sopenharmony_ci		z_erofs_pagevec_ctor_pagedown(ctor, true);
1478c2ecf20Sopenharmony_ci	}
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	t = ctor->pages[ctor->index];
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	*type = tagptr_unfold_tags(t);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	/* should remind that collector->next never equal to 1, 2 */
1548c2ecf20Sopenharmony_ci	if (*type == (uintptr_t)ctor->next)
1558c2ecf20Sopenharmony_ci		ctor->next = tagptr_unfold_ptr(t);
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	ctor->pages[ctor->index++] = tagptr_fold(erofs_vtptr_t, NULL, 0);
1588c2ecf20Sopenharmony_ci	return tagptr_unfold_ptr(t);
1598c2ecf20Sopenharmony_ci}
1608c2ecf20Sopenharmony_ci#endif
1618c2ecf20Sopenharmony_ci
162