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