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_ZDATA_H 88c2ecf20Sopenharmony_ci#define __EROFS_FS_ZDATA_H 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "internal.h" 118c2ecf20Sopenharmony_ci#include "zpvec.h" 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#define Z_EROFS_NR_INLINE_PAGEVECS 3 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci/* 168c2ecf20Sopenharmony_ci * Structure fields follow one of the following exclusion rules. 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci * I: Modifiable by initialization/destruction paths and read-only 198c2ecf20Sopenharmony_ci * for everyone else; 208c2ecf20Sopenharmony_ci * 218c2ecf20Sopenharmony_ci * L: Field should be protected by pageset lock; 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * A: Field should be accessed / updated in atomic for parallelized code. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistruct z_erofs_collection { 268c2ecf20Sopenharmony_ci struct mutex lock; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci /* I: page offset of start position of decompression */ 298c2ecf20Sopenharmony_ci unsigned short pageofs; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci /* L: maximum relative page index in pagevec[] */ 328c2ecf20Sopenharmony_ci unsigned short nr_pages; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* L: total number of pages in pagevec[] */ 358c2ecf20Sopenharmony_ci unsigned int vcnt; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci union { 388c2ecf20Sopenharmony_ci /* L: inline a certain number of pagevecs for bootstrap */ 398c2ecf20Sopenharmony_ci erofs_vtptr_t pagevec[Z_EROFS_NR_INLINE_PAGEVECS]; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci /* I: can be used to free the pcluster by RCU. */ 428c2ecf20Sopenharmony_ci struct rcu_head rcu; 438c2ecf20Sopenharmony_ci }; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define Z_EROFS_PCLUSTER_FULL_LENGTH 0x00000001 478c2ecf20Sopenharmony_ci#define Z_EROFS_PCLUSTER_LENGTH_BIT 1 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci/* 508c2ecf20Sopenharmony_ci * let's leave a type here in case of introducing 518c2ecf20Sopenharmony_ci * another tagged pointer later. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_citypedef void *z_erofs_next_pcluster_t; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_cistruct z_erofs_pcluster { 568c2ecf20Sopenharmony_ci struct erofs_workgroup obj; 578c2ecf20Sopenharmony_ci struct z_erofs_collection primary_collection; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /* A: point to next chained pcluster or TAILs */ 608c2ecf20Sopenharmony_ci z_erofs_next_pcluster_t next; 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci /* A: compressed pages (including multi-usage pages) */ 638c2ecf20Sopenharmony_ci struct page *compressed_pages[Z_EROFS_CLUSTER_MAX_PAGES]; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci /* A: lower limit of decompressed length and if full length or not */ 668c2ecf20Sopenharmony_ci unsigned int length; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* I: compression algorithm format */ 698c2ecf20Sopenharmony_ci unsigned char algorithmformat; 708c2ecf20Sopenharmony_ci /* I: bit shift of physical cluster size */ 718c2ecf20Sopenharmony_ci unsigned char clusterbits; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define z_erofs_primarycollection(pcluster) (&(pcluster)->primary_collection) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/* let's avoid the valid 32-bit kernel addresses */ 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci/* the chained workgroup has't submitted io (still open) */ 798c2ecf20Sopenharmony_ci#define Z_EROFS_PCLUSTER_TAIL ((void *)0x5F0ECAFE) 808c2ecf20Sopenharmony_ci/* the chained workgroup has already submitted io */ 818c2ecf20Sopenharmony_ci#define Z_EROFS_PCLUSTER_TAIL_CLOSED ((void *)0x5F0EDEAD) 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci#define Z_EROFS_PCLUSTER_NIL (NULL) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci#define Z_EROFS_WORKGROUP_SIZE sizeof(struct z_erofs_pcluster) 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistruct z_erofs_decompressqueue { 888c2ecf20Sopenharmony_ci struct super_block *sb; 898c2ecf20Sopenharmony_ci atomic_t pending_bios; 908c2ecf20Sopenharmony_ci z_erofs_next_pcluster_t head; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci union { 938c2ecf20Sopenharmony_ci wait_queue_head_t wait; 948c2ecf20Sopenharmony_ci struct work_struct work; 958c2ecf20Sopenharmony_ci } u; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci#define MNGD_MAPPING(sbi) ((sbi)->managed_cache->i_mapping) 998c2ecf20Sopenharmony_cistatic inline bool erofs_page_is_managed(const struct erofs_sb_info *sbi, 1008c2ecf20Sopenharmony_ci struct page *page) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci return page->mapping == MNGD_MAPPING(sbi); 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci#define Z_EROFS_ONLINEPAGE_COUNT_BITS 2 1068c2ecf20Sopenharmony_ci#define Z_EROFS_ONLINEPAGE_COUNT_MASK ((1 << Z_EROFS_ONLINEPAGE_COUNT_BITS) - 1) 1078c2ecf20Sopenharmony_ci#define Z_EROFS_ONLINEPAGE_INDEX_SHIFT (Z_EROFS_ONLINEPAGE_COUNT_BITS) 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci/* 1108c2ecf20Sopenharmony_ci * waiters (aka. ongoing_packs): # to unlock the page 1118c2ecf20Sopenharmony_ci * sub-index: 0 - for partial page, >= 1 full page sub-index 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_citypedef atomic_t z_erofs_onlinepage_t; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci/* type punning */ 1168c2ecf20Sopenharmony_ciunion z_erofs_onlinepage_converter { 1178c2ecf20Sopenharmony_ci z_erofs_onlinepage_t *o; 1188c2ecf20Sopenharmony_ci unsigned long *v; 1198c2ecf20Sopenharmony_ci}; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_cistatic inline unsigned int z_erofs_onlinepage_index(struct page *page) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci union z_erofs_onlinepage_converter u; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci DBG_BUGON(!PagePrivate(page)); 1268c2ecf20Sopenharmony_ci u.v = &page_private(page); 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci return atomic_read(u.o) >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic inline void z_erofs_onlinepage_init(struct page *page) 1328c2ecf20Sopenharmony_ci{ 1338c2ecf20Sopenharmony_ci union { 1348c2ecf20Sopenharmony_ci z_erofs_onlinepage_t o; 1358c2ecf20Sopenharmony_ci unsigned long v; 1368c2ecf20Sopenharmony_ci /* keep from being unlocked in advance */ 1378c2ecf20Sopenharmony_ci } u = { .o = ATOMIC_INIT(1) }; 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci set_page_private(page, u.v); 1408c2ecf20Sopenharmony_ci smp_wmb(); 1418c2ecf20Sopenharmony_ci SetPagePrivate(page); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic inline void z_erofs_onlinepage_fixup(struct page *page, 1458c2ecf20Sopenharmony_ci uintptr_t index, bool down) 1468c2ecf20Sopenharmony_ci{ 1478c2ecf20Sopenharmony_ci union z_erofs_onlinepage_converter u = { .v = &page_private(page) }; 1488c2ecf20Sopenharmony_ci int orig, orig_index, val; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cirepeat: 1518c2ecf20Sopenharmony_ci orig = atomic_read(u.o); 1528c2ecf20Sopenharmony_ci orig_index = orig >> Z_EROFS_ONLINEPAGE_INDEX_SHIFT; 1538c2ecf20Sopenharmony_ci if (orig_index) { 1548c2ecf20Sopenharmony_ci if (!index) 1558c2ecf20Sopenharmony_ci return; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci DBG_BUGON(orig_index != index); 1588c2ecf20Sopenharmony_ci } 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci val = (index << Z_EROFS_ONLINEPAGE_INDEX_SHIFT) | 1618c2ecf20Sopenharmony_ci ((orig & Z_EROFS_ONLINEPAGE_COUNT_MASK) + (unsigned int)down); 1628c2ecf20Sopenharmony_ci if (atomic_cmpxchg(u.o, orig, val) != orig) 1638c2ecf20Sopenharmony_ci goto repeat; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic inline void z_erofs_onlinepage_endio(struct page *page) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci union z_erofs_onlinepage_converter u; 1698c2ecf20Sopenharmony_ci unsigned int v; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci DBG_BUGON(!PagePrivate(page)); 1728c2ecf20Sopenharmony_ci u.v = &page_private(page); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci v = atomic_dec_return(u.o); 1758c2ecf20Sopenharmony_ci if (!(v & Z_EROFS_ONLINEPAGE_COUNT_MASK)) { 1768c2ecf20Sopenharmony_ci ClearPagePrivate(page); 1778c2ecf20Sopenharmony_ci if (!PageError(page)) 1788c2ecf20Sopenharmony_ci SetPageUptodate(page); 1798c2ecf20Sopenharmony_ci unlock_page(page); 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci erofs_dbg("%s, page %p value %x", __func__, page, atomic_read(u.o)); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#define Z_EROFS_VMAP_ONSTACK_PAGES \ 1858c2ecf20Sopenharmony_ci min_t(unsigned int, THREAD_SIZE / 8 / sizeof(struct page *), 96U) 1868c2ecf20Sopenharmony_ci#define Z_EROFS_VMAP_GLOBAL_PAGES 2048 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#endif 1898c2ecf20Sopenharmony_ci 190