2019-07-31 23:57:31 +08:00
|
|
|
// SPDX-License-Identifier: GPL-2.0-only
|
2018-07-26 20:21:58 +08:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2018 HUAWEI, Inc.
|
2020-07-13 21:09:44 +08:00
|
|
|
* https://www.huawei.com/
|
2022-07-15 23:41:51 +08:00
|
|
|
* Copyright (C) 2022 Alibaba Cloud
|
2018-07-26 20:21:58 +08:00
|
|
|
*/
|
2019-06-24 15:22:54 +08:00
|
|
|
#include "compress.h"
|
2022-09-15 17:41:59 +08:00
|
|
|
#include <linux/psi.h>
|
2023-02-08 17:33:22 +08:00
|
|
|
#include <linux/cpuhotplug.h>
|
2018-09-18 22:27:27 +08:00
|
|
|
#include <trace/events/erofs.h>
|
|
|
|
|
2023-02-04 17:30:38 +08:00
|
|
|
#define Z_EROFS_PCLUSTER_MAX_PAGES (Z_EROFS_PCLUSTER_MAX_SIZE / PAGE_SIZE)
|
|
|
|
#define Z_EROFS_INLINE_BVECS 2
|
|
|
|
|
|
|
|
/*
|
|
|
|
* let's leave a type here in case of introducing
|
|
|
|
* another tagged pointer later.
|
|
|
|
*/
|
|
|
|
typedef void *z_erofs_next_pcluster_t;
|
|
|
|
|
|
|
|
struct z_erofs_bvec {
|
|
|
|
struct page *page;
|
|
|
|
int offset;
|
|
|
|
unsigned int end;
|
|
|
|
};
|
|
|
|
|
|
|
|
#define __Z_EROFS_BVSET(name, total) \
|
|
|
|
struct name { \
|
|
|
|
/* point to the next page which contains the following bvecs */ \
|
|
|
|
struct page *nextpage; \
|
|
|
|
struct z_erofs_bvec bvec[total]; \
|
|
|
|
}
|
|
|
|
__Z_EROFS_BVSET(z_erofs_bvset,);
|
|
|
|
__Z_EROFS_BVSET(z_erofs_bvset_inline, Z_EROFS_INLINE_BVECS);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure fields follow one of the following exclusion rules.
|
|
|
|
*
|
|
|
|
* I: Modifiable by initialization/destruction paths and read-only
|
|
|
|
* for everyone else;
|
|
|
|
*
|
|
|
|
* L: Field should be protected by the pcluster lock;
|
|
|
|
*
|
|
|
|
* A: Field should be accessed / updated in atomic for parallelized code.
|
|
|
|
*/
|
|
|
|
struct z_erofs_pcluster {
|
|
|
|
struct erofs_workgroup obj;
|
|
|
|
struct mutex lock;
|
|
|
|
|
|
|
|
/* A: point to next chained pcluster or TAILs */
|
|
|
|
z_erofs_next_pcluster_t next;
|
|
|
|
|
|
|
|
/* L: the maximum decompression size of this round */
|
|
|
|
unsigned int length;
|
|
|
|
|
|
|
|
/* L: total number of bvecs */
|
|
|
|
unsigned int vcnt;
|
|
|
|
|
|
|
|
/* I: page offset of start position of decompression */
|
|
|
|
unsigned short pageofs_out;
|
|
|
|
|
|
|
|
/* I: page offset of inline compressed data */
|
|
|
|
unsigned short pageofs_in;
|
|
|
|
|
|
|
|
union {
|
|
|
|
/* L: inline a certain number of bvec for bootstrap */
|
|
|
|
struct z_erofs_bvset_inline bvset;
|
|
|
|
|
|
|
|
/* I: can be used to free the pcluster by RCU. */
|
|
|
|
struct rcu_head rcu;
|
|
|
|
};
|
|
|
|
|
|
|
|
union {
|
|
|
|
/* I: physical cluster size in pages */
|
|
|
|
unsigned short pclusterpages;
|
|
|
|
|
|
|
|
/* I: tailpacking inline compressed size */
|
|
|
|
unsigned short tailpacking_size;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* I: compression algorithm format */
|
|
|
|
unsigned char algorithmformat;
|
|
|
|
|
|
|
|
/* L: whether partial decompression or not */
|
|
|
|
bool partial;
|
|
|
|
|
|
|
|
/* L: indicate several pageofs_outs or not */
|
|
|
|
bool multibases;
|
|
|
|
|
|
|
|
/* A: compressed bvecs (can be cached or inplaced pages) */
|
|
|
|
struct z_erofs_bvec compressed_bvecs[];
|
|
|
|
};
|
|
|
|
|
2023-05-27 04:14:56 +08:00
|
|
|
/* the end of a chain of pclusters */
|
2023-05-27 04:14:59 +08:00
|
|
|
#define Z_EROFS_PCLUSTER_TAIL ((void *) 0x700 + POISON_POINTER_DELTA)
|
2023-02-04 17:30:38 +08:00
|
|
|
#define Z_EROFS_PCLUSTER_NIL (NULL)
|
|
|
|
|
|
|
|
struct z_erofs_decompressqueue {
|
|
|
|
struct super_block *sb;
|
|
|
|
atomic_t pending_bios;
|
|
|
|
z_erofs_next_pcluster_t head;
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct completion done;
|
|
|
|
struct work_struct work;
|
2023-02-08 17:33:22 +08:00
|
|
|
struct kthread_work kthread_work;
|
2023-02-04 17:30:38 +08:00
|
|
|
} u;
|
|
|
|
bool eio, sync;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline bool z_erofs_is_inline_pcluster(struct z_erofs_pcluster *pcl)
|
|
|
|
{
|
|
|
|
return !pcl->obj.index;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline unsigned int z_erofs_pclusterpages(struct z_erofs_pcluster *pcl)
|
|
|
|
{
|
|
|
|
if (z_erofs_is_inline_pcluster(pcl))
|
|
|
|
return 1;
|
|
|
|
return pcl->pclusterpages;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* bit 30: I/O error occurred on this page
|
|
|
|
* bit 0 - 29: remaining parts to complete this page
|
|
|
|
*/
|
|
|
|
#define Z_EROFS_PAGE_EIO (1 << 30)
|
|
|
|
|
|
|
|
static inline void z_erofs_onlinepage_init(struct page *page)
|
|
|
|
{
|
|
|
|
union {
|
|
|
|
atomic_t o;
|
|
|
|
unsigned long v;
|
|
|
|
} u = { .o = ATOMIC_INIT(1) };
|
|
|
|
|
|
|
|
set_page_private(page, u.v);
|
|
|
|
smp_wmb();
|
|
|
|
SetPagePrivate(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void z_erofs_onlinepage_split(struct page *page)
|
|
|
|
{
|
|
|
|
atomic_inc((atomic_t *)&page->private);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void z_erofs_page_mark_eio(struct page *page)
|
|
|
|
{
|
|
|
|
int orig;
|
|
|
|
|
|
|
|
do {
|
|
|
|
orig = atomic_read((atomic_t *)&page->private);
|
|
|
|
} while (atomic_cmpxchg((atomic_t *)&page->private, orig,
|
|
|
|
orig | Z_EROFS_PAGE_EIO) != orig);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline void z_erofs_onlinepage_endio(struct page *page)
|
|
|
|
{
|
|
|
|
unsigned int v;
|
|
|
|
|
|
|
|
DBG_BUGON(!PagePrivate(page));
|
|
|
|
v = atomic_dec_return((atomic_t *)&page->private);
|
|
|
|
if (!(v & ~Z_EROFS_PAGE_EIO)) {
|
|
|
|
set_page_private(page, 0);
|
|
|
|
ClearPagePrivate(page);
|
|
|
|
if (!(v & Z_EROFS_PAGE_EIO))
|
|
|
|
SetPageUptodate(page);
|
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#define Z_EROFS_ONSTACK_PAGES 32
|
|
|
|
|
2021-04-07 12:39:20 +08:00
|
|
|
/*
|
|
|
|
* since pclustersize is variable for big pcluster feature, introduce slab
|
|
|
|
* pools implementation for different pcluster sizes.
|
|
|
|
*/
|
|
|
|
struct z_erofs_pcluster_slab {
|
|
|
|
struct kmem_cache *slab;
|
|
|
|
unsigned int maxpages;
|
|
|
|
char name[48];
|
|
|
|
};
|
|
|
|
|
|
|
|
#define _PCLP(n) { .maxpages = n }
|
|
|
|
|
|
|
|
static struct z_erofs_pcluster_slab pcluster_pool[] __read_mostly = {
|
|
|
|
_PCLP(1), _PCLP(4), _PCLP(16), _PCLP(64), _PCLP(128),
|
|
|
|
_PCLP(Z_EROFS_PCLUSTER_MAX_PAGES)
|
|
|
|
};
|
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
struct z_erofs_bvec_iter {
|
|
|
|
struct page *bvpage;
|
|
|
|
struct z_erofs_bvset *bvset;
|
|
|
|
unsigned int nr, cur;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct page *z_erofs_bvec_iter_end(struct z_erofs_bvec_iter *iter)
|
|
|
|
{
|
|
|
|
if (iter->bvpage)
|
|
|
|
kunmap_local(iter->bvset);
|
|
|
|
return iter->bvpage;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct page *z_erofs_bvset_flip(struct z_erofs_bvec_iter *iter)
|
|
|
|
{
|
|
|
|
unsigned long base = (unsigned long)((struct z_erofs_bvset *)0)->bvec;
|
|
|
|
/* have to access nextpage in advance, otherwise it will be unmapped */
|
|
|
|
struct page *nextpage = iter->bvset->nextpage;
|
|
|
|
struct page *oldpage;
|
|
|
|
|
|
|
|
DBG_BUGON(!nextpage);
|
|
|
|
oldpage = z_erofs_bvec_iter_end(iter);
|
|
|
|
iter->bvpage = nextpage;
|
|
|
|
iter->bvset = kmap_local_page(nextpage);
|
|
|
|
iter->nr = (PAGE_SIZE - base) / sizeof(struct z_erofs_bvec);
|
|
|
|
iter->cur = 0;
|
|
|
|
return oldpage;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void z_erofs_bvec_iter_begin(struct z_erofs_bvec_iter *iter,
|
|
|
|
struct z_erofs_bvset_inline *bvset,
|
|
|
|
unsigned int bootstrap_nr,
|
|
|
|
unsigned int cur)
|
|
|
|
{
|
|
|
|
*iter = (struct z_erofs_bvec_iter) {
|
|
|
|
.nr = bootstrap_nr,
|
|
|
|
.bvset = (struct z_erofs_bvset *)bvset,
|
|
|
|
};
|
|
|
|
|
|
|
|
while (cur > iter->nr) {
|
|
|
|
cur -= iter->nr;
|
|
|
|
z_erofs_bvset_flip(iter);
|
|
|
|
}
|
|
|
|
iter->cur = cur;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int z_erofs_bvec_enqueue(struct z_erofs_bvec_iter *iter,
|
|
|
|
struct z_erofs_bvec *bvec,
|
2023-05-27 04:14:55 +08:00
|
|
|
struct page **candidate_bvpage,
|
|
|
|
struct page **pagepool)
|
2022-07-15 23:41:51 +08:00
|
|
|
{
|
2023-05-27 04:14:54 +08:00
|
|
|
if (iter->cur >= iter->nr) {
|
|
|
|
struct page *nextpage = *candidate_bvpage;
|
|
|
|
|
|
|
|
if (!nextpage) {
|
2023-05-27 04:14:55 +08:00
|
|
|
nextpage = erofs_allocpage(pagepool, GFP_NOFS);
|
2023-05-27 04:14:54 +08:00
|
|
|
if (!nextpage)
|
|
|
|
return -ENOMEM;
|
|
|
|
set_page_private(nextpage, Z_EROFS_SHORTLIVED_PAGE);
|
|
|
|
}
|
2022-07-15 23:41:51 +08:00
|
|
|
DBG_BUGON(iter->bvset->nextpage);
|
2023-05-27 04:14:54 +08:00
|
|
|
iter->bvset->nextpage = nextpage;
|
2022-07-15 23:41:51 +08:00
|
|
|
z_erofs_bvset_flip(iter);
|
|
|
|
|
|
|
|
iter->bvset->nextpage = NULL;
|
|
|
|
*candidate_bvpage = NULL;
|
|
|
|
}
|
|
|
|
iter->bvset->bvec[iter->cur++] = *bvec;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void z_erofs_bvec_dequeue(struct z_erofs_bvec_iter *iter,
|
|
|
|
struct z_erofs_bvec *bvec,
|
|
|
|
struct page **old_bvpage)
|
|
|
|
{
|
|
|
|
if (iter->cur == iter->nr)
|
|
|
|
*old_bvpage = z_erofs_bvset_flip(iter);
|
|
|
|
else
|
|
|
|
*old_bvpage = NULL;
|
|
|
|
*bvec = iter->bvset->bvec[iter->cur++];
|
|
|
|
}
|
|
|
|
|
2021-04-07 12:39:20 +08:00
|
|
|
static void z_erofs_destroy_pcluster_pool(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
|
|
|
|
if (!pcluster_pool[i].slab)
|
|
|
|
continue;
|
|
|
|
kmem_cache_destroy(pcluster_pool[i].slab);
|
|
|
|
pcluster_pool[i].slab = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int z_erofs_create_pcluster_pool(void)
|
|
|
|
{
|
|
|
|
struct z_erofs_pcluster_slab *pcs;
|
|
|
|
struct z_erofs_pcluster *a;
|
|
|
|
unsigned int size;
|
|
|
|
|
|
|
|
for (pcs = pcluster_pool;
|
|
|
|
pcs < pcluster_pool + ARRAY_SIZE(pcluster_pool); ++pcs) {
|
2022-07-15 23:41:54 +08:00
|
|
|
size = struct_size(a, compressed_bvecs, pcs->maxpages);
|
2021-04-07 12:39:20 +08:00
|
|
|
|
|
|
|
sprintf(pcs->name, "erofs_pcluster-%u", pcs->maxpages);
|
|
|
|
pcs->slab = kmem_cache_create(pcs->name, size, 0,
|
|
|
|
SLAB_RECLAIM_ACCOUNT, NULL);
|
|
|
|
if (pcs->slab)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
z_erofs_destroy_pcluster_pool();
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct z_erofs_pcluster *z_erofs_alloc_pcluster(unsigned int nrpages)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
|
|
|
|
struct z_erofs_pcluster_slab *pcs = pcluster_pool + i;
|
|
|
|
struct z_erofs_pcluster *pcl;
|
|
|
|
|
|
|
|
if (nrpages > pcs->maxpages)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pcl = kmem_cache_zalloc(pcs->slab, GFP_NOFS);
|
|
|
|
if (!pcl)
|
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
pcl->pclusterpages = nrpages;
|
|
|
|
return pcl;
|
|
|
|
}
|
|
|
|
return ERR_PTR(-EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void z_erofs_free_pcluster(struct z_erofs_pcluster *pcl)
|
|
|
|
{
|
2021-12-29 07:29:19 +08:00
|
|
|
unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
|
2021-04-07 12:39:20 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < ARRAY_SIZE(pcluster_pool); ++i) {
|
|
|
|
struct z_erofs_pcluster_slab *pcs = pcluster_pool + i;
|
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
if (pclusterpages > pcs->maxpages)
|
2021-04-07 12:39:20 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
kmem_cache_free(pcs->slab, pcl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
DBG_BUGON(1);
|
|
|
|
}
|
|
|
|
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
static struct workqueue_struct *z_erofs_workqueue __read_mostly;
|
|
|
|
|
2023-02-08 17:33:22 +08:00
|
|
|
#ifdef CONFIG_EROFS_FS_PCPU_KTHREAD
|
|
|
|
static struct kthread_worker __rcu **z_erofs_pcpu_workers;
|
|
|
|
|
|
|
|
static void erofs_destroy_percpu_workers(void)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2023-02-08 17:33:22 +08:00
|
|
|
struct kthread_worker *worker;
|
|
|
|
unsigned int cpu;
|
|
|
|
|
|
|
|
for_each_possible_cpu(cpu) {
|
|
|
|
worker = rcu_dereference_protected(
|
|
|
|
z_erofs_pcpu_workers[cpu], 1);
|
|
|
|
rcu_assign_pointer(z_erofs_pcpu_workers[cpu], NULL);
|
|
|
|
if (worker)
|
|
|
|
kthread_destroy_worker(worker);
|
|
|
|
}
|
|
|
|
kfree(z_erofs_pcpu_workers);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2023-02-08 17:33:22 +08:00
|
|
|
static struct kthread_worker *erofs_init_percpu_worker(int cpu)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2023-02-08 17:33:22 +08:00
|
|
|
struct kthread_worker *worker =
|
|
|
|
kthread_create_worker_on_cpu(cpu, 0, "erofs_worker/%u", cpu);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-02-08 17:33:22 +08:00
|
|
|
if (IS_ERR(worker))
|
|
|
|
return worker;
|
|
|
|
if (IS_ENABLED(CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI))
|
|
|
|
sched_set_fifo_low(worker->task);
|
|
|
|
return worker;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int erofs_init_percpu_workers(void)
|
|
|
|
{
|
|
|
|
struct kthread_worker *worker;
|
|
|
|
unsigned int cpu;
|
|
|
|
|
|
|
|
z_erofs_pcpu_workers = kcalloc(num_possible_cpus(),
|
|
|
|
sizeof(struct kthread_worker *), GFP_ATOMIC);
|
|
|
|
if (!z_erofs_pcpu_workers)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
for_each_online_cpu(cpu) { /* could miss cpu{off,on}line? */
|
|
|
|
worker = erofs_init_percpu_worker(cpu);
|
|
|
|
if (!IS_ERR(worker))
|
|
|
|
rcu_assign_pointer(z_erofs_pcpu_workers[cpu], worker);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline void erofs_destroy_percpu_workers(void) {}
|
|
|
|
static inline int erofs_init_percpu_workers(void) { return 0; }
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if defined(CONFIG_HOTPLUG_CPU) && defined(CONFIG_EROFS_FS_PCPU_KTHREAD)
|
|
|
|
static DEFINE_SPINLOCK(z_erofs_pcpu_worker_lock);
|
|
|
|
static enum cpuhp_state erofs_cpuhp_state;
|
|
|
|
|
|
|
|
static int erofs_cpu_online(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct kthread_worker *worker, *old;
|
|
|
|
|
|
|
|
worker = erofs_init_percpu_worker(cpu);
|
|
|
|
if (IS_ERR(worker))
|
|
|
|
return PTR_ERR(worker);
|
|
|
|
|
|
|
|
spin_lock(&z_erofs_pcpu_worker_lock);
|
|
|
|
old = rcu_dereference_protected(z_erofs_pcpu_workers[cpu],
|
|
|
|
lockdep_is_held(&z_erofs_pcpu_worker_lock));
|
|
|
|
if (!old)
|
|
|
|
rcu_assign_pointer(z_erofs_pcpu_workers[cpu], worker);
|
|
|
|
spin_unlock(&z_erofs_pcpu_worker_lock);
|
|
|
|
if (old)
|
|
|
|
kthread_destroy_worker(worker);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int erofs_cpu_offline(unsigned int cpu)
|
|
|
|
{
|
|
|
|
struct kthread_worker *worker;
|
|
|
|
|
|
|
|
spin_lock(&z_erofs_pcpu_worker_lock);
|
|
|
|
worker = rcu_dereference_protected(z_erofs_pcpu_workers[cpu],
|
|
|
|
lockdep_is_held(&z_erofs_pcpu_worker_lock));
|
|
|
|
rcu_assign_pointer(z_erofs_pcpu_workers[cpu], NULL);
|
|
|
|
spin_unlock(&z_erofs_pcpu_worker_lock);
|
|
|
|
|
|
|
|
synchronize_rcu();
|
|
|
|
if (worker)
|
|
|
|
kthread_destroy_worker(worker);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int erofs_cpu_hotplug_init(void)
|
|
|
|
{
|
|
|
|
int state;
|
|
|
|
|
|
|
|
state = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
|
|
|
|
"fs/erofs:online", erofs_cpu_online, erofs_cpu_offline);
|
|
|
|
if (state < 0)
|
|
|
|
return state;
|
|
|
|
|
|
|
|
erofs_cpuhp_state = state;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void erofs_cpu_hotplug_destroy(void)
|
|
|
|
{
|
|
|
|
if (erofs_cpuhp_state)
|
|
|
|
cpuhp_remove_state_nocalls(erofs_cpuhp_state);
|
|
|
|
}
|
|
|
|
#else /* !CONFIG_HOTPLUG_CPU || !CONFIG_EROFS_FS_PCPU_KTHREAD */
|
|
|
|
static inline int erofs_cpu_hotplug_init(void) { return 0; }
|
|
|
|
static inline void erofs_cpu_hotplug_destroy(void) {}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
void z_erofs_exit_zip_subsystem(void)
|
|
|
|
{
|
|
|
|
erofs_cpu_hotplug_destroy();
|
|
|
|
erofs_destroy_percpu_workers();
|
|
|
|
destroy_workqueue(z_erofs_workqueue);
|
|
|
|
z_erofs_destroy_pcluster_pool();
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2018-10-09 21:43:53 +08:00
|
|
|
int __init z_erofs_init_zip_subsystem(void)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2021-04-07 12:39:20 +08:00
|
|
|
int err = z_erofs_create_pcluster_pool();
|
|
|
|
|
|
|
|
if (err)
|
2023-02-08 17:33:22 +08:00
|
|
|
goto out_error_pcluster_pool;
|
|
|
|
|
|
|
|
z_erofs_workqueue = alloc_workqueue("erofs_worker",
|
|
|
|
WQ_UNBOUND | WQ_HIGHPRI, num_possible_cpus());
|
2023-02-16 20:13:04 +08:00
|
|
|
if (!z_erofs_workqueue) {
|
|
|
|
err = -ENOMEM;
|
2023-02-08 17:33:22 +08:00
|
|
|
goto out_error_workqueue_init;
|
2023-02-16 20:13:04 +08:00
|
|
|
}
|
2023-02-08 17:33:22 +08:00
|
|
|
|
|
|
|
err = erofs_init_percpu_workers();
|
2021-04-07 12:39:20 +08:00
|
|
|
if (err)
|
2023-02-08 17:33:22 +08:00
|
|
|
goto out_error_pcpu_worker;
|
|
|
|
|
|
|
|
err = erofs_cpu_hotplug_init();
|
|
|
|
if (err < 0)
|
|
|
|
goto out_error_cpuhp_init;
|
|
|
|
return err;
|
|
|
|
|
|
|
|
out_error_cpuhp_init:
|
|
|
|
erofs_destroy_percpu_workers();
|
|
|
|
out_error_pcpu_worker:
|
|
|
|
destroy_workqueue(z_erofs_workqueue);
|
|
|
|
out_error_workqueue_init:
|
|
|
|
z_erofs_destroy_pcluster_pool();
|
|
|
|
out_error_pcluster_pool:
|
2021-04-07 12:39:20 +08:00
|
|
|
return err;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:57 +08:00
|
|
|
enum z_erofs_pclustermode {
|
|
|
|
Z_EROFS_PCLUSTER_INFLIGHT,
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
/*
|
2022-07-15 23:41:57 +08:00
|
|
|
* a weak form of Z_EROFS_PCLUSTER_FOLLOWED, the difference is that it
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
* could be dispatched into bypass queue later due to uptodated managed
|
|
|
|
* pages. All related online pages cannot be reused for inplace I/O (or
|
2022-07-15 23:41:52 +08:00
|
|
|
* bvpage) since it can be directly decoded without I/O submission.
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
*/
|
2022-07-15 23:41:57 +08:00
|
|
|
Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE,
|
2019-02-27 13:33:32 +08:00
|
|
|
/*
|
2019-07-31 23:57:47 +08:00
|
|
|
* The current collection has been linked with the owned chain, and
|
|
|
|
* could also be linked with the remaining collections, which means
|
|
|
|
* if the processing page is the tail page of the collection, thus
|
|
|
|
* the current collection can safely use the whole page (since
|
|
|
|
* the previous collection is under control) for in-place I/O, as
|
|
|
|
* illustrated below:
|
2019-02-27 13:33:32 +08:00
|
|
|
* ________________________________________________________________
|
2019-07-31 23:57:47 +08:00
|
|
|
* | tail (partial) page | head (partial) page |
|
|
|
|
* | (of the current cl) | (of the previous collection) |
|
2023-05-27 04:14:56 +08:00
|
|
|
* | | |
|
|
|
|
* |__PCLUSTER_FOLLOWED___|___________PCLUSTER_FOLLOWED____________|
|
2019-02-27 13:33:32 +08:00
|
|
|
*
|
2019-07-31 23:57:47 +08:00
|
|
|
* [ (*) the above page can be used as inplace I/O. ]
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
*/
|
2022-07-15 23:41:57 +08:00
|
|
|
Z_EROFS_PCLUSTER_FOLLOWED,
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
};
|
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
struct z_erofs_decompress_frontend {
|
|
|
|
struct inode *const inode;
|
|
|
|
struct erofs_map_blocks map;
|
2022-07-15 23:41:51 +08:00
|
|
|
struct z_erofs_bvec_iter biter;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
struct page *pagepool;
|
2022-07-15 23:41:51 +08:00
|
|
|
struct page *candidate_bvpage;
|
2023-05-27 04:14:56 +08:00
|
|
|
struct z_erofs_pcluster *pcl;
|
2019-07-31 23:57:47 +08:00
|
|
|
z_erofs_next_pcluster_t owned_head;
|
2022-07-15 23:41:57 +08:00
|
|
|
enum z_erofs_pclustermode mode;
|
2019-07-31 23:57:47 +08:00
|
|
|
|
|
|
|
/* used for applying cache strategy on the fly */
|
|
|
|
bool backmost;
|
|
|
|
erofs_off_t headoffset;
|
2022-07-15 23:41:54 +08:00
|
|
|
|
|
|
|
/* a pointer used to pick up inplace I/O pages */
|
|
|
|
unsigned int icur;
|
2019-07-31 23:57:47 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define DECOMPRESS_FRONTEND_INIT(__i) { \
|
2022-03-02 03:49:50 +08:00
|
|
|
.inode = __i, .owned_head = Z_EROFS_PCLUSTER_TAIL, \
|
2022-07-15 23:41:57 +08:00
|
|
|
.mode = Z_EROFS_PCLUSTER_FOLLOWED, .backmost = true }
|
2019-07-31 23:57:47 +08:00
|
|
|
|
2022-12-06 14:03:52 +08:00
|
|
|
static bool z_erofs_should_alloc_cache(struct z_erofs_decompress_frontend *fe)
|
|
|
|
{
|
|
|
|
unsigned int cachestrategy = EROFS_I_SB(fe->inode)->opt.cache_strategy;
|
|
|
|
|
|
|
|
if (cachestrategy <= EROFS_ZIP_CACHE_DISABLED)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (fe->backmost)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (cachestrategy >= EROFS_ZIP_CACHE_READAROUND &&
|
|
|
|
fe->map.m_la < fe->headoffset)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
static void z_erofs_bind_cache(struct z_erofs_decompress_frontend *fe)
|
2018-07-26 20:22:07 +08:00
|
|
|
{
|
2022-03-02 03:49:51 +08:00
|
|
|
struct address_space *mc = MNGD_MAPPING(EROFS_I_SB(fe->inode));
|
2022-03-02 03:49:50 +08:00
|
|
|
struct z_erofs_pcluster *pcl = fe->pcl;
|
2022-12-06 14:03:52 +08:00
|
|
|
bool shouldalloc = z_erofs_should_alloc_cache(fe);
|
2018-12-08 00:19:16 +08:00
|
|
|
bool standalone = true;
|
2022-03-02 03:49:51 +08:00
|
|
|
/*
|
|
|
|
* optimistic allocation without direct reclaim since inplace I/O
|
|
|
|
* can be used if low memory otherwise.
|
|
|
|
*/
|
2020-12-09 20:37:17 +08:00
|
|
|
gfp_t gfp = (mapping_gfp_mask(mc) & ~__GFP_DIRECT_RECLAIM) |
|
|
|
|
__GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN;
|
2022-07-15 23:41:54 +08:00
|
|
|
unsigned int i;
|
2018-12-08 00:19:16 +08:00
|
|
|
|
2022-07-15 23:41:57 +08:00
|
|
|
if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED)
|
2018-12-08 00:19:16 +08:00
|
|
|
return;
|
|
|
|
|
2022-07-15 23:41:54 +08:00
|
|
|
for (i = 0; i < pcl->pclusterpages; ++i) {
|
2018-12-08 00:19:16 +08:00
|
|
|
struct page *page;
|
2023-02-04 17:30:37 +08:00
|
|
|
void *t; /* mark pages just found for debugging */
|
2020-12-09 20:37:17 +08:00
|
|
|
struct page *newpage = NULL;
|
2018-12-08 00:19:16 +08:00
|
|
|
|
|
|
|
/* the compressed page was loaded before */
|
2022-07-15 23:41:54 +08:00
|
|
|
if (READ_ONCE(pcl->compressed_bvecs[i].page))
|
2018-07-26 20:22:07 +08:00
|
|
|
continue;
|
|
|
|
|
2022-07-15 23:41:54 +08:00
|
|
|
page = find_get_page(mc, pcl->obj.index + i);
|
2018-12-08 00:19:16 +08:00
|
|
|
|
|
|
|
if (page) {
|
2023-02-04 17:30:37 +08:00
|
|
|
t = (void *)((unsigned long)page | 1);
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
} else {
|
|
|
|
/* I/O is needed, no possible to decompress directly */
|
2018-12-08 00:19:16 +08:00
|
|
|
standalone = false;
|
2022-12-06 14:03:52 +08:00
|
|
|
if (!shouldalloc)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* try to use cached I/O if page allocation
|
|
|
|
* succeeds or fallback to in-place I/O instead
|
|
|
|
* to avoid any direct reclaim.
|
|
|
|
*/
|
2023-05-27 04:14:55 +08:00
|
|
|
newpage = erofs_allocpage(&fe->pagepool, gfp);
|
2022-12-06 14:03:52 +08:00
|
|
|
if (!newpage)
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
continue;
|
2022-12-06 14:03:52 +08:00
|
|
|
set_page_private(newpage, Z_EROFS_PREALLOCATED_PAGE);
|
2023-02-04 17:30:37 +08:00
|
|
|
t = (void *)((unsigned long)newpage | 1);
|
2018-07-26 20:22:07 +08:00
|
|
|
}
|
|
|
|
|
2023-02-04 17:30:37 +08:00
|
|
|
if (!cmpxchg_relaxed(&pcl->compressed_bvecs[i].page, NULL, t))
|
2018-07-26 20:22:07 +08:00
|
|
|
continue;
|
|
|
|
|
2021-10-22 17:01:20 +08:00
|
|
|
if (page)
|
2018-12-08 00:19:16 +08:00
|
|
|
put_page(page);
|
2021-10-22 17:01:20 +08:00
|
|
|
else if (newpage)
|
2023-05-27 04:14:55 +08:00
|
|
|
erofs_pagepool_add(&fe->pagepool, newpage);
|
2018-07-26 20:22:07 +08:00
|
|
|
}
|
2018-12-08 00:19:16 +08:00
|
|
|
|
erofs: complete a missing case for inplace I/O
Add a missing case which could cause unnecessary page allocation but
not directly use inplace I/O instead, which increases runtime extra
memory footprint.
The detail is, considering an online file-backed page, the right half
of the page is chosen to be cached (e.g. the end page of a readahead
request) and some of its data doesn't exist in managed cache, so the
pcluster will be definitely kept in the submission chain. (IOWs, it
cannot be decompressed without I/O, e.g., due to the bypass queue).
Currently, DELAYEDALLOC/TRYALLOC cases can be downgraded as NOINPLACE,
and stop online pages from inplace I/O. After this patch, unneeded page
allocations won't be observed in pickup_page_for_submission() then.
Link: https://lore.kernel.org/r/20210321183227.5182-1-hsiangkao@aol.com
Signed-off-by: Gao Xiang <hsiangkao@redhat.com>
2021-03-22 02:32:27 +08:00
|
|
|
/*
|
|
|
|
* don't do inplace I/O if all compressed pages are available in
|
|
|
|
* managed cache since it can be moved to the bypass queue instead.
|
|
|
|
*/
|
|
|
|
if (standalone)
|
2022-07-15 23:41:57 +08:00
|
|
|
fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
|
2018-07-26 20:22:07 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* called by erofs_shrinker to get rid of all compressed_pages */
|
2018-07-29 13:34:58 +08:00
|
|
|
int erofs_try_to_free_all_cached_pages(struct erofs_sb_info *sbi,
|
2019-07-31 23:57:47 +08:00
|
|
|
struct erofs_workgroup *grp)
|
2018-07-26 20:22:07 +08:00
|
|
|
{
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_pcluster *const pcl =
|
|
|
|
container_of(grp, struct z_erofs_pcluster, obj);
|
2018-07-26 20:22:07 +08:00
|
|
|
int i;
|
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
DBG_BUGON(z_erofs_is_inline_pcluster(pcl));
|
2018-07-26 20:22:07 +08:00
|
|
|
/*
|
2023-05-29 20:37:27 +08:00
|
|
|
* refcount of workgroup is now freezed as 0,
|
2018-07-26 20:22:07 +08:00
|
|
|
* therefore no need to worry about available decompression users.
|
|
|
|
*/
|
2021-04-07 12:39:20 +08:00
|
|
|
for (i = 0; i < pcl->pclusterpages; ++i) {
|
2022-07-15 23:41:54 +08:00
|
|
|
struct page *page = pcl->compressed_bvecs[i].page;
|
2018-07-26 20:22:07 +08:00
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
if (!page)
|
2018-07-26 20:22:07 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* block other users from reclaiming or migrating the page */
|
|
|
|
if (!trylock_page(page))
|
|
|
|
return -EBUSY;
|
|
|
|
|
2021-08-10 14:54:50 +08:00
|
|
|
if (!erofs_page_is_managed(sbi, page))
|
2019-07-31 23:57:47 +08:00
|
|
|
continue;
|
2018-07-26 20:22:07 +08:00
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
/* barrier is implied in the following 'unlock_page' */
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
|
2020-12-08 17:58:32 +08:00
|
|
|
detach_page_private(page);
|
2018-07-26 20:22:07 +08:00
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-05-27 04:14:57 +08:00
|
|
|
static bool z_erofs_cache_release_folio(struct folio *folio, gfp_t gfp)
|
2018-07-26 20:22:07 +08:00
|
|
|
{
|
2023-05-27 04:14:57 +08:00
|
|
|
struct z_erofs_pcluster *pcl = folio_get_private(folio);
|
|
|
|
bool ret;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!folio_test_private(folio))
|
|
|
|
return true;
|
2018-07-26 20:22:07 +08:00
|
|
|
|
2023-05-27 04:14:57 +08:00
|
|
|
ret = false;
|
2023-05-29 20:37:27 +08:00
|
|
|
spin_lock(&pcl->obj.lockref.lock);
|
|
|
|
if (pcl->obj.lockref.count > 0)
|
|
|
|
goto out;
|
|
|
|
|
2022-07-15 23:41:54 +08:00
|
|
|
DBG_BUGON(z_erofs_is_inline_pcluster(pcl));
|
|
|
|
for (i = 0; i < pcl->pclusterpages; ++i) {
|
2023-05-27 04:14:57 +08:00
|
|
|
if (pcl->compressed_bvecs[i].page == &folio->page) {
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
|
2023-05-27 04:14:57 +08:00
|
|
|
ret = true;
|
2022-07-15 23:41:54 +08:00
|
|
|
break;
|
2018-07-26 20:22:07 +08:00
|
|
|
}
|
|
|
|
}
|
2022-07-15 23:41:54 +08:00
|
|
|
if (ret)
|
2023-05-27 04:14:57 +08:00
|
|
|
folio_detach_private(folio);
|
2023-05-29 20:37:27 +08:00
|
|
|
out:
|
|
|
|
spin_unlock(&pcl->obj.lockref.lock);
|
2018-07-26 20:22:07 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-05-27 04:14:57 +08:00
|
|
|
/*
|
|
|
|
* It will be called only on inode eviction. In case that there are still some
|
|
|
|
* decompression requests in progress, wait with rescheduling for a bit here.
|
|
|
|
* An extra lock could be introduced instead but it seems unnecessary.
|
|
|
|
*/
|
|
|
|
static void z_erofs_cache_invalidate_folio(struct folio *folio,
|
|
|
|
size_t offset, size_t length)
|
|
|
|
{
|
|
|
|
const size_t stop = length + offset;
|
|
|
|
|
|
|
|
/* Check for potential overflow in debug mode */
|
|
|
|
DBG_BUGON(stop > folio_size(folio) || stop < length);
|
|
|
|
|
|
|
|
if (offset == 0 && stop == folio_size(folio))
|
|
|
|
while (!z_erofs_cache_release_folio(folio, GFP_NOFS))
|
|
|
|
cond_resched();
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct address_space_operations z_erofs_cache_aops = {
|
|
|
|
.release_folio = z_erofs_cache_release_folio,
|
|
|
|
.invalidate_folio = z_erofs_cache_invalidate_folio,
|
|
|
|
};
|
|
|
|
|
|
|
|
int erofs_init_managed_cache(struct super_block *sb)
|
|
|
|
{
|
|
|
|
struct inode *const inode = new_inode(sb);
|
|
|
|
|
|
|
|
if (!inode)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
set_nlink(inode, 1);
|
|
|
|
inode->i_size = OFFSET_MAX;
|
|
|
|
inode->i_mapping->a_ops = &z_erofs_cache_aops;
|
|
|
|
mapping_set_gfp_mask(inode->i_mapping, GFP_NOFS);
|
|
|
|
EROFS_SB(sb)->managed_cache = inode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
static bool z_erofs_try_inplace_io(struct z_erofs_decompress_frontend *fe,
|
2022-07-15 23:41:54 +08:00
|
|
|
struct z_erofs_bvec *bvec)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-03-02 03:49:50 +08:00
|
|
|
struct z_erofs_pcluster *const pcl = fe->pcl;
|
2019-07-31 23:57:47 +08:00
|
|
|
|
2022-07-15 23:41:54 +08:00
|
|
|
while (fe->icur > 0) {
|
|
|
|
if (!cmpxchg(&pcl->compressed_bvecs[--fe->icur].page,
|
|
|
|
NULL, bvec->page)) {
|
|
|
|
pcl->compressed_bvecs[fe->icur] = *bvec;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return true;
|
2022-07-15 23:41:54 +08:00
|
|
|
}
|
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
/* callers must be with pcluster lock held */
|
2022-03-02 03:49:50 +08:00
|
|
|
static int z_erofs_attach_page(struct z_erofs_decompress_frontend *fe,
|
2022-07-15 23:41:56 +08:00
|
|
|
struct z_erofs_bvec *bvec, bool exclusive)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2022-07-15 23:41:57 +08:00
|
|
|
if (exclusive) {
|
2022-07-15 23:41:51 +08:00
|
|
|
/* give priority for inplaceio to use file pages first */
|
2022-07-15 23:41:54 +08:00
|
|
|
if (z_erofs_try_inplace_io(fe, bvec))
|
2022-07-15 23:41:51 +08:00
|
|
|
return 0;
|
|
|
|
/* otherwise, check if it can be used as a bvpage */
|
2022-07-15 23:41:57 +08:00
|
|
|
if (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED &&
|
2022-07-15 23:41:51 +08:00
|
|
|
!fe->candidate_bvpage)
|
|
|
|
fe->candidate_bvpage = bvec->page;
|
|
|
|
}
|
2023-05-27 04:14:55 +08:00
|
|
|
ret = z_erofs_bvec_enqueue(&fe->biter, bvec, &fe->candidate_bvpage,
|
|
|
|
&fe->pagepool);
|
2022-07-15 23:41:51 +08:00
|
|
|
fe->pcl->vcnt += (ret >= 0);
|
|
|
|
return ret;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
static void z_erofs_try_to_claim_pcluster(struct z_erofs_decompress_frontend *f)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-03-02 03:49:50 +08:00
|
|
|
struct z_erofs_pcluster *pcl = f->pcl;
|
|
|
|
z_erofs_next_pcluster_t *owned_head = &f->owned_head;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-12-08 17:58:34 +08:00
|
|
|
/* type 1, nil pcluster (this pcluster doesn't belong to any chain.) */
|
|
|
|
if (cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_NIL,
|
|
|
|
*owned_head) == Z_EROFS_PCLUSTER_NIL) {
|
2019-07-31 23:57:47 +08:00
|
|
|
*owned_head = &pcl->next;
|
2020-12-08 17:58:34 +08:00
|
|
|
/* so we can attach this pcluster to our submission chain. */
|
2022-07-15 23:41:57 +08:00
|
|
|
f->mode = Z_EROFS_PCLUSTER_FOLLOWED;
|
2020-12-08 17:58:34 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-05-27 04:14:56 +08:00
|
|
|
/* type 2, it belongs to an ongoing chain */
|
2022-07-15 23:41:57 +08:00
|
|
|
f->mode = Z_EROFS_PCLUSTER_INFLIGHT;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
static int z_erofs_register_pcluster(struct z_erofs_decompress_frontend *fe)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-07-15 23:41:48 +08:00
|
|
|
struct erofs_map_blocks *map = &fe->map;
|
2021-12-29 07:29:19 +08:00
|
|
|
bool ztailpacking = map->m_flags & EROFS_MAP_META;
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_pcluster *pcl;
|
2020-02-20 10:46:42 +08:00
|
|
|
struct erofs_workgroup *grp;
|
2019-07-31 23:57:47 +08:00
|
|
|
int err;
|
2018-09-19 13:49:07 +08:00
|
|
|
|
2022-12-05 11:49:57 +08:00
|
|
|
if (!(map->m_flags & EROFS_MAP_ENCODED) ||
|
|
|
|
(!ztailpacking && !(map->m_pa >> PAGE_SHIFT))) {
|
2021-10-09 04:08:37 +08:00
|
|
|
DBG_BUGON(1);
|
|
|
|
return -EFSCORRUPTED;
|
|
|
|
}
|
|
|
|
|
2021-04-07 12:39:20 +08:00
|
|
|
/* no available pcluster, let's allocate one */
|
2021-12-29 07:29:19 +08:00
|
|
|
pcl = z_erofs_alloc_pcluster(ztailpacking ? 1 :
|
|
|
|
map->m_plen >> PAGE_SHIFT);
|
2021-04-07 12:39:20 +08:00
|
|
|
if (IS_ERR(pcl))
|
|
|
|
return PTR_ERR(pcl);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-29 20:37:27 +08:00
|
|
|
spin_lock_init(&pcl->obj.lockref.lock);
|
2021-10-09 04:08:37 +08:00
|
|
|
pcl->algorithmformat = map->m_algorithmformat;
|
2022-07-15 23:42:02 +08:00
|
|
|
pcl->length = 0;
|
|
|
|
pcl->partial = true;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
/* new pclusters should be claimed as type 1, primary and followed */
|
2022-03-02 03:49:50 +08:00
|
|
|
pcl->next = fe->owned_head;
|
2022-05-29 13:54:23 +08:00
|
|
|
pcl->pageofs_out = map->m_la & ~PAGE_MASK;
|
2022-07-15 23:41:57 +08:00
|
|
|
fe->mode = Z_EROFS_PCLUSTER_FOLLOWED;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2018-11-23 01:21:47 +08:00
|
|
|
/*
|
|
|
|
* lock all primary followed works before visible to others
|
2019-07-31 23:57:47 +08:00
|
|
|
* and mutex_trylock *never* fails for a new pcluster.
|
2018-11-23 01:21:47 +08:00
|
|
|
*/
|
2022-05-29 13:54:23 +08:00
|
|
|
mutex_init(&pcl->lock);
|
|
|
|
DBG_BUGON(!mutex_trylock(&pcl->lock));
|
2020-02-20 10:46:42 +08:00
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
if (ztailpacking) {
|
|
|
|
pcl->obj.index = 0; /* which indicates ztailpacking */
|
2023-03-13 21:53:08 +08:00
|
|
|
pcl->pageofs_in = erofs_blkoff(fe->inode->i_sb, map->m_pa);
|
2021-12-29 07:29:19 +08:00
|
|
|
pcl->tailpacking_size = map->m_plen;
|
|
|
|
} else {
|
|
|
|
pcl->obj.index = map->m_pa >> PAGE_SHIFT;
|
2018-11-23 01:21:47 +08:00
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
grp = erofs_insert_workgroup(fe->inode->i_sb, &pcl->obj);
|
2021-12-29 07:29:19 +08:00
|
|
|
if (IS_ERR(grp)) {
|
|
|
|
err = PTR_ERR(grp);
|
|
|
|
goto err_out;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (grp != &pcl->obj) {
|
2022-03-02 03:49:50 +08:00
|
|
|
fe->pcl = container_of(grp,
|
2021-12-29 07:29:19 +08:00
|
|
|
struct z_erofs_pcluster, obj);
|
|
|
|
err = -EEXIST;
|
|
|
|
goto err_out;
|
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
2022-03-02 03:49:50 +08:00
|
|
|
fe->owned_head = &pcl->next;
|
|
|
|
fe->pcl = pcl;
|
2019-10-08 20:56:12 +08:00
|
|
|
return 0;
|
2020-02-20 10:46:42 +08:00
|
|
|
|
|
|
|
err_out:
|
2022-05-29 13:54:23 +08:00
|
|
|
mutex_unlock(&pcl->lock);
|
2021-04-07 12:39:20 +08:00
|
|
|
z_erofs_free_pcluster(pcl);
|
2020-02-20 10:46:42 +08:00
|
|
|
return err;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
static int z_erofs_collector_begin(struct z_erofs_decompress_frontend *fe)
|
2019-07-31 23:57:47 +08:00
|
|
|
{
|
2022-07-15 23:41:48 +08:00
|
|
|
struct erofs_map_blocks *map = &fe->map;
|
2022-07-15 23:41:49 +08:00
|
|
|
struct erofs_workgroup *grp = NULL;
|
2019-10-08 20:56:12 +08:00
|
|
|
int ret;
|
2019-02-27 13:33:32 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
DBG_BUGON(fe->pcl);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
/* must be Z_EROFS_PCLUSTER_TAIL or pointed to previous pcluster */
|
2022-03-02 03:49:50 +08:00
|
|
|
DBG_BUGON(fe->owned_head == Z_EROFS_PCLUSTER_NIL);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:41:49 +08:00
|
|
|
if (!(map->m_flags & EROFS_MAP_META)) {
|
|
|
|
grp = erofs_find_workgroup(fe->inode->i_sb,
|
|
|
|
map->m_pa >> PAGE_SHIFT);
|
|
|
|
} else if ((map->m_pa & ~PAGE_MASK) + map->m_plen > PAGE_SIZE) {
|
|
|
|
DBG_BUGON(1);
|
|
|
|
return -EFSCORRUPTED;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2020-02-20 10:46:42 +08:00
|
|
|
if (grp) {
|
2022-03-02 03:49:50 +08:00
|
|
|
fe->pcl = container_of(grp, struct z_erofs_pcluster, obj);
|
2022-07-15 23:41:49 +08:00
|
|
|
ret = -EEXIST;
|
2020-02-20 10:46:42 +08:00
|
|
|
} else {
|
2022-07-15 23:41:48 +08:00
|
|
|
ret = z_erofs_register_pcluster(fe);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:49 +08:00
|
|
|
if (ret == -EEXIST) {
|
2022-07-15 23:42:03 +08:00
|
|
|
mutex_lock(&fe->pcl->lock);
|
|
|
|
z_erofs_try_to_claim_pcluster(fe);
|
2022-07-15 23:41:49 +08:00
|
|
|
} else if (ret) {
|
2019-10-08 20:56:12 +08:00
|
|
|
return ret;
|
2020-02-20 10:46:42 +08:00
|
|
|
}
|
2022-07-15 23:41:51 +08:00
|
|
|
z_erofs_bvec_iter_begin(&fe->biter, &fe->pcl->bvset,
|
2022-07-15 23:41:52 +08:00
|
|
|
Z_EROFS_INLINE_BVECS, fe->pcl->vcnt);
|
2021-04-07 12:39:21 +08:00
|
|
|
/* since file-backed online pages are traversed in reverse order */
|
2022-07-15 23:41:54 +08:00
|
|
|
fe->icur = z_erofs_pclusterpages(fe->pcl);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2019-07-31 23:57:47 +08:00
|
|
|
* keep in mind that no referenced pclusters will be freed
|
|
|
|
* only after a RCU grace period.
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
*/
|
|
|
|
static void z_erofs_rcu_callback(struct rcu_head *head)
|
|
|
|
{
|
2022-05-29 13:54:23 +08:00
|
|
|
z_erofs_free_pcluster(container_of(head,
|
|
|
|
struct z_erofs_pcluster, rcu));
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void erofs_workgroup_free_rcu(struct erofs_workgroup *grp)
|
|
|
|
{
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_pcluster *const pcl =
|
|
|
|
container_of(grp, struct z_erofs_pcluster, obj);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
call_rcu(&pcl->rcu, z_erofs_rcu_callback);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
static bool z_erofs_collector_end(struct z_erofs_decompress_frontend *fe)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-05-29 13:54:23 +08:00
|
|
|
struct z_erofs_pcluster *pcl = fe->pcl;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
if (!pcl)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return false;
|
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
z_erofs_bvec_iter_end(&fe->biter);
|
2022-05-29 13:54:23 +08:00
|
|
|
mutex_unlock(&pcl->lock);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:54 +08:00
|
|
|
if (fe->candidate_bvpage)
|
2022-07-15 23:41:51 +08:00
|
|
|
fe->candidate_bvpage = NULL;
|
|
|
|
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
/*
|
2019-07-31 23:57:47 +08:00
|
|
|
* if all pending pages are added, don't hold its reference
|
|
|
|
* any longer if the pcluster isn't hosted by ourselves.
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
*/
|
2022-07-15 23:41:57 +08:00
|
|
|
if (fe->mode < Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE)
|
2022-05-29 13:54:23 +08:00
|
|
|
erofs_workgroup_put(&pcl->obj);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
fe->pcl = NULL;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2022-09-23 10:11:22 +08:00
|
|
|
static int z_erofs_read_fragment(struct inode *inode, erofs_off_t pos,
|
|
|
|
struct page *page, unsigned int pageofs,
|
|
|
|
unsigned int len)
|
|
|
|
{
|
2023-03-13 21:53:08 +08:00
|
|
|
struct super_block *sb = inode->i_sb;
|
2022-09-23 10:11:22 +08:00
|
|
|
struct inode *packed_inode = EROFS_I_SB(inode)->packed_inode;
|
|
|
|
struct erofs_buf buf = __EROFS_BUF_INITIALIZER;
|
|
|
|
u8 *src, *dst;
|
|
|
|
unsigned int i, cnt;
|
|
|
|
|
2022-10-21 16:53:25 +08:00
|
|
|
if (!packed_inode)
|
|
|
|
return -EFSCORRUPTED;
|
|
|
|
|
2023-04-07 22:17:04 +08:00
|
|
|
buf.inode = packed_inode;
|
2022-09-23 10:11:22 +08:00
|
|
|
pos += EROFS_I(inode)->z_fragmentoff;
|
|
|
|
for (i = 0; i < len; i += cnt) {
|
|
|
|
cnt = min_t(unsigned int, len - i,
|
2023-03-13 21:53:08 +08:00
|
|
|
sb->s_blocksize - erofs_blkoff(sb, pos));
|
2023-04-07 22:17:04 +08:00
|
|
|
src = erofs_bread(&buf, erofs_blknr(sb, pos), EROFS_KMAP);
|
2022-09-23 10:11:22 +08:00
|
|
|
if (IS_ERR(src)) {
|
|
|
|
erofs_put_metabuf(&buf);
|
|
|
|
return PTR_ERR(src);
|
|
|
|
}
|
|
|
|
|
|
|
|
dst = kmap_local_page(page);
|
2023-03-13 21:53:08 +08:00
|
|
|
memcpy(dst + pageofs + i, src + erofs_blkoff(sb, pos), cnt);
|
2022-09-23 10:11:22 +08:00
|
|
|
kunmap_local(dst);
|
|
|
|
pos += cnt;
|
|
|
|
}
|
|
|
|
erofs_put_metabuf(&buf);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
|
2023-05-27 04:14:55 +08:00
|
|
|
struct page *page)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2019-07-31 23:57:47 +08:00
|
|
|
struct inode *const inode = fe->inode;
|
2019-01-15 09:42:21 +08:00
|
|
|
struct erofs_map_blocks *const map = &fe->map;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
const loff_t offset = page_offset(page);
|
2022-07-15 23:41:56 +08:00
|
|
|
bool tight = true, exclusive;
|
2022-07-15 23:42:02 +08:00
|
|
|
unsigned int cur, end, spiltted;
|
2018-09-18 22:27:25 +08:00
|
|
|
int err = 0;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
|
|
|
/* register locked file pages as online pages in pack */
|
|
|
|
z_erofs_onlinepage_init(page);
|
|
|
|
|
|
|
|
spiltted = 0;
|
|
|
|
end = PAGE_SIZE;
|
|
|
|
repeat:
|
|
|
|
cur = end - 1;
|
|
|
|
|
2022-05-29 13:54:24 +08:00
|
|
|
if (offset + cur < map->m_la ||
|
|
|
|
offset + cur >= map->m_la + map->m_llen) {
|
|
|
|
if (z_erofs_collector_end(fe))
|
|
|
|
fe->backmost = false;
|
|
|
|
map->m_la = offset + cur;
|
|
|
|
map->m_llen = 0;
|
|
|
|
err = z_erofs_map_blocks_iter(inode, map, 0);
|
|
|
|
if (err)
|
2022-07-15 23:41:55 +08:00
|
|
|
goto out;
|
2022-05-29 13:54:24 +08:00
|
|
|
} else {
|
|
|
|
if (fe->pcl)
|
|
|
|
goto hitted;
|
2022-05-29 13:54:23 +08:00
|
|
|
/* didn't get a valid pcluster previously (very rare) */
|
staging: erofs: fix illegal address access under memory pressure
Considering a read request with two decompressed file pages,
If a decompression work cannot be started on the previous page
due to memory pressure but in-memory LTP map lookup is done,
builder->work should be still NULL.
Moreover, if the current page also belongs to the same map,
it won't try to start the decompression work again and then
run into trouble.
This patch aims to solve the above issue only with little changes
as much as possible in order to make the fix backport easier.
kernel message is:
<4>[1051408.015930s]SLUB: Unable to allocate memory on node -1, gfp=0x2408040(GFP_NOFS|__GFP_ZERO)
<4>[1051408.015930s] cache: erofs_compress, object size: 144, buffer size: 144, default order: 0, min order: 0
<4>[1051408.015930s] node 0: slabs: 98, objs: 2744, free: 0
* Cannot allocate the decompression work
<3>[1051408.015960s]erofs: z_erofs_vle_normalaccess_readpages, readahead error at page 1008 of nid 5391488
* Note that the previous page was failed to read
<0>[1051408.015960s]Internal error: Accessing user space memory outside uaccess.h routines: 96000005 [#1] PREEMPT SMP
...
<4>[1051408.015991s]Hardware name: kirin710 (DT)
...
<4>[1051408.016021s]PC is at z_erofs_vle_work_add_page+0xa0/0x17c
<4>[1051408.016021s]LR is at z_erofs_do_read_page+0x12c/0xcf0
...
<4>[1051408.018096s][<ffffff80c6fb0fd4>] z_erofs_vle_work_add_page+0xa0/0x17c
<4>[1051408.018096s][<ffffff80c6fb3814>] z_erofs_vle_normalaccess_readpages+0x1a0/0x37c
<4>[1051408.018096s][<ffffff80c6d670b8>] read_pages+0x70/0x190
<4>[1051408.018127s][<ffffff80c6d6736c>] __do_page_cache_readahead+0x194/0x1a8
<4>[1051408.018127s][<ffffff80c6d59318>] filemap_fault+0x398/0x684
<4>[1051408.018127s][<ffffff80c6d8a9e0>] __do_fault+0x8c/0x138
<4>[1051408.018127s][<ffffff80c6d8f90c>] handle_pte_fault+0x730/0xb7c
<4>[1051408.018127s][<ffffff80c6d8fe04>] __handle_mm_fault+0xac/0xf4
<4>[1051408.018157s][<ffffff80c6d8fec8>] handle_mm_fault+0x7c/0x118
<4>[1051408.018157s][<ffffff80c8c52998>] do_page_fault+0x354/0x474
<4>[1051408.018157s][<ffffff80c8c52af8>] do_translation_fault+0x40/0x48
<4>[1051408.018157s][<ffffff80c6c002f4>] do_mem_abort+0x80/0x100
<4>[1051408.018310s]---[ end trace 9f4009a3283bd78b ]---
Fixes: 3883a79abd02 ("staging: erofs: introduce VLE decompression support")
Cc: <stable@vger.kernel.org> # 4.19+
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Reviewed-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2019-02-27 13:33:31 +08:00
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-09-23 10:11:22 +08:00
|
|
|
if (!(map->m_flags & EROFS_MAP_MAPPED) ||
|
|
|
|
map->m_flags & EROFS_MAP_FRAGMENT)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
goto hitted;
|
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
err = z_erofs_collector_begin(fe);
|
2019-08-30 00:38:27 +08:00
|
|
|
if (err)
|
2022-07-15 23:41:55 +08:00
|
|
|
goto out;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
if (z_erofs_is_inline_pcluster(fe->pcl)) {
|
2022-01-02 12:00:17 +08:00
|
|
|
void *mp;
|
2021-12-29 07:29:19 +08:00
|
|
|
|
2022-01-02 12:00:17 +08:00
|
|
|
mp = erofs_read_metabuf(&fe->map.buf, inode->i_sb,
|
2023-03-13 21:53:08 +08:00
|
|
|
erofs_blknr(inode->i_sb, map->m_pa),
|
|
|
|
EROFS_NO_KMAP);
|
2022-01-02 12:00:17 +08:00
|
|
|
if (IS_ERR(mp)) {
|
|
|
|
err = PTR_ERR(mp);
|
2021-12-29 07:29:19 +08:00
|
|
|
erofs_err(inode->i_sb,
|
|
|
|
"failed to get inline page, err %d", err);
|
2022-07-15 23:41:55 +08:00
|
|
|
goto out;
|
2021-12-29 07:29:19 +08:00
|
|
|
}
|
2022-01-02 12:00:17 +08:00
|
|
|
get_page(fe->map.buf.page);
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(fe->pcl->compressed_bvecs[0].page,
|
|
|
|
fe->map.buf.page);
|
2022-07-15 23:41:57 +08:00
|
|
|
fe->mode = Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE;
|
2021-12-29 07:29:19 +08:00
|
|
|
} else {
|
2022-03-02 03:49:51 +08:00
|
|
|
/* bind cache first when cached decompression is preferred */
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_bind_cache(fe);
|
2021-12-29 07:29:19 +08:00
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
hitted:
|
2019-09-22 18:04:34 +08:00
|
|
|
/*
|
|
|
|
* Ensure the current partial page belongs to this submit chain rather
|
|
|
|
* than other concurrent submit chains or the noio(bypass) chain since
|
|
|
|
* those chains are handled asynchronously thus the page cannot be used
|
2022-07-15 23:41:52 +08:00
|
|
|
* for inplace I/O or bvpage (should be processed in a strict order.)
|
2019-09-22 18:04:34 +08:00
|
|
|
*/
|
2023-05-27 04:14:56 +08:00
|
|
|
tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE);
|
2019-09-22 18:04:34 +08:00
|
|
|
|
2023-07-10 17:34:10 +08:00
|
|
|
cur = end - min_t(erofs_off_t, offset + end - map->m_la, end);
|
2019-08-30 00:38:27 +08:00
|
|
|
if (!(map->m_flags & EROFS_MAP_MAPPED)) {
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
zero_user_segment(page, cur, end);
|
|
|
|
goto next_part;
|
|
|
|
}
|
2022-09-23 10:11:22 +08:00
|
|
|
if (map->m_flags & EROFS_MAP_FRAGMENT) {
|
|
|
|
unsigned int pageofs, skip, len;
|
|
|
|
|
|
|
|
if (offset > map->m_la) {
|
|
|
|
pageofs = 0;
|
|
|
|
skip = offset - map->m_la;
|
|
|
|
} else {
|
|
|
|
pageofs = map->m_la & ~PAGE_MASK;
|
|
|
|
skip = 0;
|
|
|
|
}
|
|
|
|
len = min_t(unsigned int, map->m_llen - skip, end - cur);
|
|
|
|
err = z_erofs_read_fragment(inode, skip, page, pageofs, len);
|
|
|
|
if (err)
|
|
|
|
goto out;
|
|
|
|
++spiltted;
|
|
|
|
tight = false;
|
|
|
|
goto next_part;
|
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:41:56 +08:00
|
|
|
exclusive = (!cur && (!spiltted || tight));
|
2019-02-27 13:33:32 +08:00
|
|
|
if (cur)
|
2022-07-15 23:41:57 +08:00
|
|
|
tight &= (fe->mode >= Z_EROFS_PCLUSTER_FOLLOWED);
|
2019-02-27 13:33:32 +08:00
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
err = z_erofs_attach_page(fe, &((struct z_erofs_bvec) {
|
|
|
|
.page = page,
|
|
|
|
.offset = offset - map->m_la,
|
|
|
|
.end = end,
|
2022-07-15 23:41:56 +08:00
|
|
|
}), exclusive);
|
2023-05-27 04:14:54 +08:00
|
|
|
if (err)
|
2022-07-15 23:41:55 +08:00
|
|
|
goto out;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:41:55 +08:00
|
|
|
z_erofs_onlinepage_split(page);
|
2018-09-18 22:27:25 +08:00
|
|
|
/* bump up the number of spiltted parts of a page */
|
|
|
|
++spiltted;
|
2022-07-15 23:42:03 +08:00
|
|
|
if (fe->pcl->pageofs_out != (map->m_la & ~PAGE_MASK))
|
|
|
|
fe->pcl->multibases = true;
|
2022-07-15 23:42:02 +08:00
|
|
|
if (fe->pcl->length < offset + end - map->m_la) {
|
|
|
|
fe->pcl->length = offset + end - map->m_la;
|
|
|
|
fe->pcl->pageofs_out = map->m_la & ~PAGE_MASK;
|
|
|
|
}
|
2022-10-14 14:49:15 +08:00
|
|
|
if ((map->m_flags & EROFS_MAP_FULL_MAPPED) &&
|
|
|
|
!(map->m_flags & EROFS_MAP_PARTIAL_REF) &&
|
|
|
|
fe->pcl->length == map->m_llen)
|
|
|
|
fe->pcl->partial = false;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
next_part:
|
2022-07-15 23:42:02 +08:00
|
|
|
/* shorten the remaining extent to update progress */
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
map->m_llen = offset + cur - map->m_la;
|
2022-07-15 23:42:02 +08:00
|
|
|
map->m_flags &= ~EROFS_MAP_FULL_MAPPED;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2018-08-05 23:21:01 +08:00
|
|
|
end = cur;
|
|
|
|
if (end > 0)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
goto repeat;
|
|
|
|
|
2018-09-18 22:27:25 +08:00
|
|
|
out:
|
2022-07-15 23:41:55 +08:00
|
|
|
if (err)
|
|
|
|
z_erofs_page_mark_eio(page);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
z_erofs_onlinepage_endio(page);
|
2018-09-18 22:27:25 +08:00
|
|
|
return err;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2023-05-24 14:39:44 +08:00
|
|
|
static bool z_erofs_is_sync_decompress(struct erofs_sb_info *sbi,
|
2021-12-06 22:35:52 +08:00
|
|
|
unsigned int readahead_pages)
|
|
|
|
{
|
2022-04-29 23:12:16 +08:00
|
|
|
/* auto: enable for read_folio, disable for readahead */
|
2021-12-06 22:35:52 +08:00
|
|
|
if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO) &&
|
|
|
|
!readahead_pages)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if ((sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_FORCE_ON) &&
|
|
|
|
(readahead_pages <= sbi->opt.max_sync_decompress_pages))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-12-08 17:58:32 +08:00
|
|
|
static bool z_erofs_page_is_invalidated(struct page *page)
|
|
|
|
{
|
|
|
|
return !page->mapping && !z_erofs_is_shortlived_page(page);
|
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
struct z_erofs_decompress_backend {
|
|
|
|
struct page *onstack_pages[Z_EROFS_ONSTACK_PAGES];
|
|
|
|
struct super_block *sb;
|
|
|
|
struct z_erofs_pcluster *pcl;
|
|
|
|
|
|
|
|
/* pages with the longest decompressed length for deduplication */
|
|
|
|
struct page **decompressed_pages;
|
|
|
|
/* pages to keep the compressed data */
|
|
|
|
struct page **compressed_pages;
|
|
|
|
|
2022-07-15 23:42:03 +08:00
|
|
|
struct list_head decompressed_secondary_bvecs;
|
2022-07-15 23:41:59 +08:00
|
|
|
struct page **pagepool;
|
2022-07-15 23:42:02 +08:00
|
|
|
unsigned int onstack_used, nr_pages;
|
2022-07-15 23:41:59 +08:00
|
|
|
};
|
|
|
|
|
2022-07-15 23:42:03 +08:00
|
|
|
struct z_erofs_bvec_item {
|
|
|
|
struct z_erofs_bvec bvec;
|
|
|
|
struct list_head list;
|
|
|
|
};
|
|
|
|
|
|
|
|
static void z_erofs_do_decompressed_bvec(struct z_erofs_decompress_backend *be,
|
|
|
|
struct z_erofs_bvec *bvec)
|
2022-07-15 23:42:01 +08:00
|
|
|
{
|
2022-07-15 23:42:03 +08:00
|
|
|
struct z_erofs_bvec_item *item;
|
2023-07-19 14:54:59 +08:00
|
|
|
unsigned int pgnr;
|
2022-07-15 23:42:01 +08:00
|
|
|
|
2023-07-19 14:54:59 +08:00
|
|
|
if (!((bvec->offset + be->pcl->pageofs_out) & ~PAGE_MASK) &&
|
|
|
|
(bvec->end == PAGE_SIZE ||
|
|
|
|
bvec->offset + bvec->end == be->pcl->length)) {
|
2022-07-15 23:42:03 +08:00
|
|
|
pgnr = (bvec->offset + be->pcl->pageofs_out) >> PAGE_SHIFT;
|
|
|
|
DBG_BUGON(pgnr >= be->nr_pages);
|
2022-10-12 12:50:56 +08:00
|
|
|
if (!be->decompressed_pages[pgnr]) {
|
|
|
|
be->decompressed_pages[pgnr] = bvec->page;
|
2022-07-15 23:42:03 +08:00
|
|
|
return;
|
2022-10-12 12:50:56 +08:00
|
|
|
}
|
2022-07-15 23:42:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* (cold path) one pcluster is requested multiple times */
|
|
|
|
item = kmalloc(sizeof(*item), GFP_KERNEL | __GFP_NOFAIL);
|
|
|
|
item->bvec = *bvec;
|
|
|
|
list_add(&item->list, &be->decompressed_secondary_bvecs);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void z_erofs_fill_other_copies(struct z_erofs_decompress_backend *be,
|
|
|
|
int err)
|
|
|
|
{
|
|
|
|
unsigned int off0 = be->pcl->pageofs_out;
|
|
|
|
struct list_head *p, *n;
|
|
|
|
|
|
|
|
list_for_each_safe(p, n, &be->decompressed_secondary_bvecs) {
|
|
|
|
struct z_erofs_bvec_item *bvi;
|
|
|
|
unsigned int end, cur;
|
|
|
|
void *dst, *src;
|
|
|
|
|
|
|
|
bvi = container_of(p, struct z_erofs_bvec_item, list);
|
|
|
|
cur = bvi->bvec.offset < 0 ? -bvi->bvec.offset : 0;
|
|
|
|
end = min_t(unsigned int, be->pcl->length - bvi->bvec.offset,
|
|
|
|
bvi->bvec.end);
|
|
|
|
dst = kmap_local_page(bvi->bvec.page);
|
|
|
|
while (cur < end) {
|
|
|
|
unsigned int pgnr, scur, len;
|
|
|
|
|
|
|
|
pgnr = (bvi->bvec.offset + cur + off0) >> PAGE_SHIFT;
|
|
|
|
DBG_BUGON(pgnr >= be->nr_pages);
|
|
|
|
|
|
|
|
scur = bvi->bvec.offset + cur -
|
|
|
|
((pgnr << PAGE_SHIFT) - off0);
|
|
|
|
len = min_t(unsigned int, end - cur, PAGE_SIZE - scur);
|
|
|
|
if (!be->decompressed_pages[pgnr]) {
|
|
|
|
err = -EFSCORRUPTED;
|
|
|
|
cur += len;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
src = kmap_local_page(be->decompressed_pages[pgnr]);
|
|
|
|
memcpy(dst + cur, src + scur, len);
|
|
|
|
kunmap_local(src);
|
|
|
|
cur += len;
|
|
|
|
}
|
|
|
|
kunmap_local(dst);
|
|
|
|
if (err)
|
|
|
|
z_erofs_page_mark_eio(bvi->bvec.page);
|
|
|
|
z_erofs_onlinepage_endio(bvi->bvec.page);
|
|
|
|
list_del(p);
|
|
|
|
kfree(bvi);
|
2022-07-15 23:42:01 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-15 23:42:03 +08:00
|
|
|
static void z_erofs_parse_out_bvecs(struct z_erofs_decompress_backend *be)
|
2022-07-15 23:41:50 +08:00
|
|
|
{
|
2022-07-15 23:41:59 +08:00
|
|
|
struct z_erofs_pcluster *pcl = be->pcl;
|
2022-07-15 23:41:51 +08:00
|
|
|
struct z_erofs_bvec_iter biter;
|
|
|
|
struct page *old_bvpage;
|
2022-07-15 23:42:03 +08:00
|
|
|
int i;
|
2022-07-15 23:41:50 +08:00
|
|
|
|
2022-07-15 23:41:52 +08:00
|
|
|
z_erofs_bvec_iter_begin(&biter, &pcl->bvset, Z_EROFS_INLINE_BVECS, 0);
|
2022-07-15 23:41:50 +08:00
|
|
|
for (i = 0; i < pcl->vcnt; ++i) {
|
2022-07-15 23:41:51 +08:00
|
|
|
struct z_erofs_bvec bvec;
|
2022-07-15 23:41:50 +08:00
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
z_erofs_bvec_dequeue(&biter, &bvec, &old_bvpage);
|
2022-07-15 23:41:50 +08:00
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
if (old_bvpage)
|
2022-07-15 23:41:59 +08:00
|
|
|
z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
|
2022-07-15 23:41:50 +08:00
|
|
|
|
2022-07-15 23:41:51 +08:00
|
|
|
DBG_BUGON(z_erofs_page_is_invalidated(bvec.page));
|
2022-07-15 23:42:03 +08:00
|
|
|
z_erofs_do_decompressed_bvec(be, &bvec);
|
2022-07-15 23:41:50 +08:00
|
|
|
}
|
2022-07-15 23:41:51 +08:00
|
|
|
|
|
|
|
old_bvpage = z_erofs_bvec_iter_end(&biter);
|
|
|
|
if (old_bvpage)
|
2022-07-15 23:41:59 +08:00
|
|
|
z_erofs_put_shortlivedpage(be->pagepool, old_bvpage);
|
2022-07-15 23:41:50 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
static int z_erofs_parse_in_bvecs(struct z_erofs_decompress_backend *be,
|
|
|
|
bool *overlapped)
|
2022-07-15 23:41:53 +08:00
|
|
|
{
|
2022-07-15 23:41:59 +08:00
|
|
|
struct z_erofs_pcluster *pcl = be->pcl;
|
2022-07-15 23:41:53 +08:00
|
|
|
unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
|
|
|
|
int i, err = 0;
|
|
|
|
|
|
|
|
*overlapped = false;
|
|
|
|
for (i = 0; i < pclusterpages; ++i) {
|
2022-07-15 23:41:54 +08:00
|
|
|
struct z_erofs_bvec *bvec = &pcl->compressed_bvecs[i];
|
|
|
|
struct page *page = bvec->page;
|
2022-07-15 23:41:53 +08:00
|
|
|
|
|
|
|
/* compressed pages ought to be present before decompressing */
|
|
|
|
if (!page) {
|
|
|
|
DBG_BUGON(1);
|
|
|
|
continue;
|
|
|
|
}
|
2022-07-15 23:42:00 +08:00
|
|
|
be->compressed_pages[i] = page;
|
2022-07-15 23:41:53 +08:00
|
|
|
|
|
|
|
if (z_erofs_is_inline_pcluster(pcl)) {
|
|
|
|
if (!PageUptodate(page))
|
|
|
|
err = -EIO;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBG_BUGON(z_erofs_page_is_invalidated(page));
|
|
|
|
if (!z_erofs_is_shortlived_page(page)) {
|
2022-07-15 23:41:59 +08:00
|
|
|
if (erofs_page_is_managed(EROFS_SB(be->sb), page)) {
|
2022-07-15 23:41:53 +08:00
|
|
|
if (!PageUptodate(page))
|
|
|
|
err = -EIO;
|
|
|
|
continue;
|
|
|
|
}
|
2022-07-15 23:42:03 +08:00
|
|
|
z_erofs_do_decompressed_bvec(be, bvec);
|
2022-07-15 23:41:53 +08:00
|
|
|
*overlapped = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-07-15 23:42:00 +08:00
|
|
|
if (err)
|
2022-07-15 23:41:59 +08:00
|
|
|
return err;
|
|
|
|
return 0;
|
2022-07-15 23:41:53 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
static int z_erofs_decompress_pcluster(struct z_erofs_decompress_backend *be,
|
|
|
|
int err)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-07-15 23:41:59 +08:00
|
|
|
struct erofs_sb_info *const sbi = EROFS_SB(be->sb);
|
|
|
|
struct z_erofs_pcluster *pcl = be->pcl;
|
2021-12-29 07:29:19 +08:00
|
|
|
unsigned int pclusterpages = z_erofs_pclusterpages(pcl);
|
2023-04-26 16:44:49 +08:00
|
|
|
const struct z_erofs_decompressor *decompressor =
|
|
|
|
&erofs_decompressors[pcl->algorithmformat];
|
2022-07-15 23:42:02 +08:00
|
|
|
unsigned int i, inputsize;
|
2022-07-15 23:41:55 +08:00
|
|
|
int err2;
|
2022-07-15 23:42:02 +08:00
|
|
|
struct page *page;
|
|
|
|
bool overlapped;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
mutex_lock(&pcl->lock);
|
2022-07-15 23:42:02 +08:00
|
|
|
be->nr_pages = PAGE_ALIGN(pcl->length + pcl->pageofs_out) >> PAGE_SHIFT;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:42:00 +08:00
|
|
|
/* allocate (de)compressed page arrays if cannot be kept on stack */
|
|
|
|
be->decompressed_pages = NULL;
|
|
|
|
be->compressed_pages = NULL;
|
|
|
|
be->onstack_used = 0;
|
2022-07-15 23:42:02 +08:00
|
|
|
if (be->nr_pages <= Z_EROFS_ONSTACK_PAGES) {
|
2022-07-15 23:41:59 +08:00
|
|
|
be->decompressed_pages = be->onstack_pages;
|
2022-07-15 23:42:02 +08:00
|
|
|
be->onstack_used = be->nr_pages;
|
2022-07-15 23:41:59 +08:00
|
|
|
memset(be->decompressed_pages, 0,
|
2022-07-15 23:42:02 +08:00
|
|
|
sizeof(struct page *) * be->nr_pages);
|
2022-07-15 23:42:00 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (pclusterpages + be->onstack_used <= Z_EROFS_ONSTACK_PAGES)
|
|
|
|
be->compressed_pages = be->onstack_pages + be->onstack_used;
|
|
|
|
|
|
|
|
if (!be->decompressed_pages)
|
2022-07-15 23:41:59 +08:00
|
|
|
be->decompressed_pages =
|
2023-03-09 13:31:47 +08:00
|
|
|
kvcalloc(be->nr_pages, sizeof(struct page *),
|
|
|
|
GFP_KERNEL | __GFP_NOFAIL);
|
2022-07-15 23:42:00 +08:00
|
|
|
if (!be->compressed_pages)
|
|
|
|
be->compressed_pages =
|
2023-03-09 13:31:47 +08:00
|
|
|
kvcalloc(pclusterpages, sizeof(struct page *),
|
|
|
|
GFP_KERNEL | __GFP_NOFAIL);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:42:03 +08:00
|
|
|
z_erofs_parse_out_bvecs(be);
|
2022-07-15 23:41:59 +08:00
|
|
|
err2 = z_erofs_parse_in_bvecs(be, &overlapped);
|
2022-07-15 23:41:55 +08:00
|
|
|
if (err2)
|
|
|
|
err = err2;
|
2019-08-30 00:38:27 +08:00
|
|
|
if (err)
|
2019-03-25 11:40:07 +08:00
|
|
|
goto out;
|
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
if (z_erofs_is_inline_pcluster(pcl))
|
|
|
|
inputsize = pcl->tailpacking_size;
|
|
|
|
else
|
|
|
|
inputsize = pclusterpages * PAGE_SIZE;
|
|
|
|
|
2023-04-26 16:44:49 +08:00
|
|
|
err = decompressor->decompress(&(struct z_erofs_decompress_req) {
|
2022-07-15 23:41:59 +08:00
|
|
|
.sb = be->sb,
|
|
|
|
.in = be->compressed_pages,
|
|
|
|
.out = be->decompressed_pages,
|
2021-12-29 07:29:19 +08:00
|
|
|
.pageofs_in = pcl->pageofs_in,
|
2022-05-29 13:54:23 +08:00
|
|
|
.pageofs_out = pcl->pageofs_out,
|
2021-04-07 12:39:20 +08:00
|
|
|
.inputsize = inputsize,
|
2022-07-15 23:42:02 +08:00
|
|
|
.outputsize = pcl->length,
|
2019-07-31 23:57:47 +08:00
|
|
|
.alg = pcl->algorithmformat,
|
2019-06-24 15:22:57 +08:00
|
|
|
.inplace_io = overlapped,
|
2022-07-15 23:42:02 +08:00
|
|
|
.partial_decoding = pcl->partial,
|
2022-07-15 23:42:03 +08:00
|
|
|
.fillgaps = pcl->multibases,
|
2022-07-15 23:41:59 +08:00
|
|
|
}, be->pagepool);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
|
|
|
out:
|
2021-12-29 07:29:19 +08:00
|
|
|
/* must handle all compressed pages before actual file pages */
|
|
|
|
if (z_erofs_is_inline_pcluster(pcl)) {
|
2022-07-15 23:41:54 +08:00
|
|
|
page = pcl->compressed_bvecs[0].page;
|
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[0].page, NULL);
|
2021-12-29 07:29:19 +08:00
|
|
|
put_page(page);
|
|
|
|
} else {
|
|
|
|
for (i = 0; i < pclusterpages; ++i) {
|
2022-07-15 23:41:54 +08:00
|
|
|
page = pcl->compressed_bvecs[i].page;
|
2019-03-25 11:40:08 +08:00
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
if (erofs_page_is_managed(sbi, page))
|
|
|
|
continue;
|
2019-02-27 13:33:30 +08:00
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
/* recycle all individual short-lived pages */
|
2022-07-15 23:41:59 +08:00
|
|
|
(void)z_erofs_put_shortlivedpage(be->pagepool, page);
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[i].page, NULL);
|
2021-12-29 07:29:19 +08:00
|
|
|
}
|
2019-02-27 13:33:30 +08:00
|
|
|
}
|
2022-07-15 23:42:00 +08:00
|
|
|
if (be->compressed_pages < be->onstack_pages ||
|
|
|
|
be->compressed_pages >= be->onstack_pages + Z_EROFS_ONSTACK_PAGES)
|
2023-03-09 13:31:47 +08:00
|
|
|
kvfree(be->compressed_pages);
|
2022-07-15 23:42:03 +08:00
|
|
|
z_erofs_fill_other_copies(be, err);
|
2019-02-27 13:33:30 +08:00
|
|
|
|
2022-07-15 23:42:02 +08:00
|
|
|
for (i = 0; i < be->nr_pages; ++i) {
|
2022-07-15 23:41:59 +08:00
|
|
|
page = be->decompressed_pages[i];
|
2019-02-27 13:33:30 +08:00
|
|
|
if (!page)
|
|
|
|
continue;
|
|
|
|
|
2020-12-08 17:58:32 +08:00
|
|
|
DBG_BUGON(z_erofs_page_is_invalidated(page));
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-12-08 17:58:32 +08:00
|
|
|
/* recycle all individual short-lived pages */
|
2022-07-15 23:41:59 +08:00
|
|
|
if (z_erofs_put_shortlivedpage(be->pagepool, page))
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
continue;
|
2022-07-15 23:41:55 +08:00
|
|
|
if (err)
|
|
|
|
z_erofs_page_mark_eio(page);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
z_erofs_onlinepage_endio(page);
|
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
if (be->decompressed_pages != be->onstack_pages)
|
2023-03-09 13:31:47 +08:00
|
|
|
kvfree(be->decompressed_pages);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:42:02 +08:00
|
|
|
pcl->length = 0;
|
|
|
|
pcl->partial = true;
|
2022-07-15 23:42:03 +08:00
|
|
|
pcl->multibases = false;
|
2022-07-15 23:41:51 +08:00
|
|
|
pcl->bvset.nextpage = NULL;
|
2022-05-29 13:54:23 +08:00
|
|
|
pcl->vcnt = 0;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-05-29 13:54:23 +08:00
|
|
|
/* pcluster lock MUST be taken before the following line */
|
2019-07-31 23:57:47 +08:00
|
|
|
WRITE_ONCE(pcl->next, Z_EROFS_PCLUSTER_NIL);
|
2022-05-29 13:54:23 +08:00
|
|
|
mutex_unlock(&pcl->lock);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
2019-11-08 11:37:33 +08:00
|
|
|
static void z_erofs_decompress_queue(const struct z_erofs_decompressqueue *io,
|
2021-10-22 17:01:20 +08:00
|
|
|
struct page **pagepool)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-07-15 23:41:59 +08:00
|
|
|
struct z_erofs_decompress_backend be = {
|
|
|
|
.sb = io->sb,
|
|
|
|
.pagepool = pagepool,
|
2022-07-15 23:42:03 +08:00
|
|
|
.decompressed_secondary_bvecs =
|
|
|
|
LIST_HEAD_INIT(be.decompressed_secondary_bvecs),
|
2022-07-15 23:41:59 +08:00
|
|
|
};
|
2019-07-31 23:57:47 +08:00
|
|
|
z_erofs_next_pcluster_t owned = io->head;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:56 +08:00
|
|
|
while (owned != Z_EROFS_PCLUSTER_TAIL) {
|
2019-07-31 23:57:47 +08:00
|
|
|
DBG_BUGON(owned == Z_EROFS_PCLUSTER_NIL);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
be.pcl = container_of(owned, struct z_erofs_pcluster, next);
|
|
|
|
owned = READ_ONCE(be.pcl->next);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-07-15 23:41:59 +08:00
|
|
|
z_erofs_decompress_pcluster(&be, io->eio ? -EIO : 0);
|
|
|
|
erofs_workgroup_put(&be.pcl->obj);
|
2018-08-06 11:27:53 +08:00
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2019-11-08 11:37:33 +08:00
|
|
|
static void z_erofs_decompressqueue_work(struct work_struct *work)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2019-10-08 20:56:15 +08:00
|
|
|
struct z_erofs_decompressqueue *bgq =
|
|
|
|
container_of(work, struct z_erofs_decompressqueue, u.work);
|
2021-10-22 17:01:20 +08:00
|
|
|
struct page *pagepool = NULL;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:56 +08:00
|
|
|
DBG_BUGON(bgq->head == Z_EROFS_PCLUSTER_TAIL);
|
2019-11-08 11:37:33 +08:00
|
|
|
z_erofs_decompress_queue(bgq, &pagepool);
|
2021-10-22 17:01:20 +08:00
|
|
|
erofs_release_pages(&pagepool);
|
2019-10-08 20:56:15 +08:00
|
|
|
kvfree(bgq);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2023-02-08 17:33:22 +08:00
|
|
|
#ifdef CONFIG_EROFS_FS_PCPU_KTHREAD
|
|
|
|
static void z_erofs_decompressqueue_kthread_work(struct kthread_work *work)
|
|
|
|
{
|
|
|
|
z_erofs_decompressqueue_work((struct work_struct *)work);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2022-01-21 17:14:12 +08:00
|
|
|
static void z_erofs_decompress_kickoff(struct z_erofs_decompressqueue *io,
|
2023-02-04 17:30:36 +08:00
|
|
|
int bios)
|
2022-01-21 17:14:12 +08:00
|
|
|
{
|
|
|
|
struct erofs_sb_info *const sbi = EROFS_SB(io->sb);
|
|
|
|
|
|
|
|
/* wake up the caller thread for sync decompression */
|
2023-02-04 17:30:36 +08:00
|
|
|
if (io->sync) {
|
2022-01-21 17:14:12 +08:00
|
|
|
if (!atomic_add_return(bios, &io->pending_bios))
|
2022-04-01 19:55:27 +08:00
|
|
|
complete(&io->u.done);
|
2022-01-21 17:14:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (atomic_add_return(bios, &io->pending_bios))
|
|
|
|
return;
|
2023-02-08 17:33:22 +08:00
|
|
|
/* Use (kthread_)work and sync decompression for atomic contexts only */
|
2023-06-22 06:08:47 +08:00
|
|
|
if (!in_task() || irqs_disabled() || rcu_read_lock_any_held()) {
|
2023-02-08 17:33:22 +08:00
|
|
|
#ifdef CONFIG_EROFS_FS_PCPU_KTHREAD
|
|
|
|
struct kthread_worker *worker;
|
|
|
|
|
|
|
|
rcu_read_lock();
|
|
|
|
worker = rcu_dereference(
|
|
|
|
z_erofs_pcpu_workers[raw_smp_processor_id()]);
|
|
|
|
if (!worker) {
|
|
|
|
INIT_WORK(&io->u.work, z_erofs_decompressqueue_work);
|
|
|
|
queue_work(z_erofs_workqueue, &io->u.work);
|
|
|
|
} else {
|
|
|
|
kthread_queue_work(worker, &io->u.kthread_work);
|
|
|
|
}
|
|
|
|
rcu_read_unlock();
|
|
|
|
#else
|
2022-01-21 17:14:12 +08:00
|
|
|
queue_work(z_erofs_workqueue, &io->u.work);
|
2023-02-08 17:33:22 +08:00
|
|
|
#endif
|
2022-01-21 17:14:12 +08:00
|
|
|
/* enable sync decompression for readahead */
|
|
|
|
if (sbi->opt.sync_decompress == EROFS_SYNC_DECOMPRESS_AUTO)
|
|
|
|
sbi->opt.sync_decompress = EROFS_SYNC_DECOMPRESS_FORCE_ON;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
z_erofs_decompressqueue_work(&io->u.work);
|
|
|
|
}
|
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
static struct page *pickup_page_for_submission(struct z_erofs_pcluster *pcl,
|
|
|
|
unsigned int nr,
|
2021-10-22 17:01:20 +08:00
|
|
|
struct page **pagepool,
|
2022-03-11 02:27:43 +08:00
|
|
|
struct address_space *mc)
|
2018-12-08 00:19:15 +08:00
|
|
|
{
|
2019-07-31 23:57:47 +08:00
|
|
|
const pgoff_t index = pcl->obj.index;
|
2022-03-11 02:27:43 +08:00
|
|
|
gfp_t gfp = mapping_gfp_mask(mc);
|
2018-12-08 00:19:15 +08:00
|
|
|
bool tocache = false;
|
|
|
|
|
|
|
|
struct address_space *mapping;
|
|
|
|
struct page *oldpage, *page;
|
2018-12-08 00:19:16 +08:00
|
|
|
int justfound;
|
|
|
|
|
2018-12-08 00:19:15 +08:00
|
|
|
repeat:
|
2022-07-15 23:41:54 +08:00
|
|
|
page = READ_ONCE(pcl->compressed_bvecs[nr].page);
|
2018-12-08 00:19:15 +08:00
|
|
|
oldpage = page;
|
|
|
|
|
|
|
|
if (!page)
|
|
|
|
goto out_allocpage;
|
|
|
|
|
2023-02-04 17:30:37 +08:00
|
|
|
justfound = (unsigned long)page & 1UL;
|
|
|
|
page = (struct page *)((unsigned long)page & ~1UL);
|
2018-12-08 00:19:16 +08:00
|
|
|
|
2020-12-09 20:37:17 +08:00
|
|
|
/*
|
|
|
|
* preallocated cached pages, which is used to avoid direct reclaim
|
|
|
|
* otherwise, it will go inplace I/O path instead.
|
|
|
|
*/
|
|
|
|
if (page->private == Z_EROFS_PREALLOCATED_PAGE) {
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
|
2020-12-09 20:37:17 +08:00
|
|
|
set_page_private(page, 0);
|
|
|
|
tocache = true;
|
|
|
|
goto out_tocache;
|
|
|
|
}
|
2018-12-08 00:19:15 +08:00
|
|
|
mapping = READ_ONCE(page->mapping);
|
|
|
|
|
|
|
|
/*
|
2020-12-08 17:58:32 +08:00
|
|
|
* file-backed online pages in plcuster are all locked steady,
|
2018-12-08 00:19:15 +08:00
|
|
|
* therefore it is impossible for `mapping' to be NULL.
|
|
|
|
*/
|
|
|
|
if (mapping && mapping != mc)
|
|
|
|
/* ought to be unmanaged pages */
|
|
|
|
goto out;
|
|
|
|
|
2020-12-08 17:58:32 +08:00
|
|
|
/* directly return for shortlived page as well */
|
|
|
|
if (z_erofs_is_shortlived_page(page))
|
|
|
|
goto out;
|
|
|
|
|
2018-12-08 00:19:15 +08:00
|
|
|
lock_page(page);
|
|
|
|
|
2018-12-08 00:19:16 +08:00
|
|
|
/* only true if page reclaim goes wrong, should never happen */
|
|
|
|
DBG_BUGON(justfound && PagePrivate(page));
|
|
|
|
|
2018-12-08 00:19:15 +08:00
|
|
|
/* the page is still in manage cache */
|
|
|
|
if (page->mapping == mc) {
|
2022-07-15 23:41:54 +08:00
|
|
|
WRITE_ONCE(pcl->compressed_bvecs[nr].page, page);
|
2018-12-08 00:19:15 +08:00
|
|
|
|
|
|
|
if (!PagePrivate(page)) {
|
2018-12-08 00:19:16 +08:00
|
|
|
/*
|
|
|
|
* impossible to be !PagePrivate(page) for
|
|
|
|
* the current restriction as well if
|
2022-07-15 23:41:54 +08:00
|
|
|
* the page is already in compressed_bvecs[].
|
2018-12-08 00:19:16 +08:00
|
|
|
*/
|
|
|
|
DBG_BUGON(!justfound);
|
|
|
|
|
|
|
|
justfound = 0;
|
2019-07-31 23:57:47 +08:00
|
|
|
set_page_private(page, (unsigned long)pcl);
|
2018-12-08 00:19:15 +08:00
|
|
|
SetPagePrivate(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* no need to submit io if it is already up-to-date */
|
|
|
|
if (PageUptodate(page)) {
|
|
|
|
unlock_page(page);
|
|
|
|
page = NULL;
|
|
|
|
}
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* the managed page has been truncated, it's unsafe to
|
|
|
|
* reuse this one, let's allocate a new cache-managed page.
|
|
|
|
*/
|
|
|
|
DBG_BUGON(page->mapping);
|
2018-12-08 00:19:16 +08:00
|
|
|
DBG_BUGON(!justfound);
|
2018-12-08 00:19:15 +08:00
|
|
|
|
|
|
|
tocache = true;
|
|
|
|
unlock_page(page);
|
|
|
|
put_page(page);
|
|
|
|
out_allocpage:
|
2019-11-21 21:59:54 +08:00
|
|
|
page = erofs_allocpage(pagepool, gfp | __GFP_NOFAIL);
|
2022-07-15 23:41:54 +08:00
|
|
|
if (oldpage != cmpxchg(&pcl->compressed_bvecs[nr].page,
|
|
|
|
oldpage, page)) {
|
2021-10-22 17:01:20 +08:00
|
|
|
erofs_pagepool_add(pagepool, page);
|
2019-11-21 21:59:54 +08:00
|
|
|
cond_resched();
|
|
|
|
goto repeat;
|
|
|
|
}
|
2020-12-09 20:37:17 +08:00
|
|
|
out_tocache:
|
2020-12-08 17:58:33 +08:00
|
|
|
if (!tocache || add_to_page_cache_lru(page, mc, index + nr, gfp)) {
|
|
|
|
/* turn into temporary page if fails (1 ref) */
|
|
|
|
set_page_private(page, Z_EROFS_SHORTLIVED_PAGE);
|
|
|
|
goto out;
|
2020-10-22 22:57:21 +08:00
|
|
|
}
|
2020-12-08 17:58:33 +08:00
|
|
|
attach_page_private(page, pcl);
|
|
|
|
/* drop a refcount added by allocpage (then we have 2 refs here) */
|
|
|
|
put_page(page);
|
|
|
|
|
2018-12-08 00:19:15 +08:00
|
|
|
out: /* the only exit (for tracing and debugging) */
|
|
|
|
return page;
|
|
|
|
}
|
|
|
|
|
2023-02-04 17:30:36 +08:00
|
|
|
static struct z_erofs_decompressqueue *jobqueue_init(struct super_block *sb,
|
|
|
|
struct z_erofs_decompressqueue *fgq, bool *fg)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2019-10-08 20:56:15 +08:00
|
|
|
struct z_erofs_decompressqueue *q;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-10-08 20:56:15 +08:00
|
|
|
if (fg && !*fg) {
|
|
|
|
q = kvzalloc(sizeof(*q), GFP_KERNEL | __GFP_NOWARN);
|
|
|
|
if (!q) {
|
|
|
|
*fg = true;
|
|
|
|
goto fg_out;
|
|
|
|
}
|
2023-02-08 17:33:22 +08:00
|
|
|
#ifdef CONFIG_EROFS_FS_PCPU_KTHREAD
|
|
|
|
kthread_init_work(&q->u.kthread_work,
|
|
|
|
z_erofs_decompressqueue_kthread_work);
|
|
|
|
#else
|
2019-11-08 11:37:33 +08:00
|
|
|
INIT_WORK(&q->u.work, z_erofs_decompressqueue_work);
|
2023-02-08 17:33:22 +08:00
|
|
|
#endif
|
2019-10-08 20:56:15 +08:00
|
|
|
} else {
|
|
|
|
fg_out:
|
|
|
|
q = fgq;
|
2022-04-01 19:55:27 +08:00
|
|
|
init_completion(&fgq->u.done);
|
2019-10-08 20:56:15 +08:00
|
|
|
atomic_set(&fgq->pending_bios, 0);
|
2022-07-15 23:41:55 +08:00
|
|
|
q->eio = false;
|
2023-02-04 17:30:36 +08:00
|
|
|
q->sync = true;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
2019-10-08 20:56:15 +08:00
|
|
|
q->sb = sb;
|
2023-05-27 04:14:56 +08:00
|
|
|
q->head = Z_EROFS_PCLUSTER_TAIL;
|
2019-10-08 20:56:15 +08:00
|
|
|
return q;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
/* define decompression jobqueue types */
|
2018-12-08 00:19:18 +08:00
|
|
|
enum {
|
|
|
|
JQ_BYPASS,
|
|
|
|
JQ_SUBMIT,
|
|
|
|
NR_JOBQUEUES,
|
|
|
|
};
|
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
static void move_to_bypass_jobqueue(struct z_erofs_pcluster *pcl,
|
|
|
|
z_erofs_next_pcluster_t qtail[],
|
|
|
|
z_erofs_next_pcluster_t owned_head)
|
2018-12-08 00:19:18 +08:00
|
|
|
{
|
2019-07-31 23:57:47 +08:00
|
|
|
z_erofs_next_pcluster_t *const submit_qtail = qtail[JQ_SUBMIT];
|
|
|
|
z_erofs_next_pcluster_t *const bypass_qtail = qtail[JQ_BYPASS];
|
2018-12-08 00:19:18 +08:00
|
|
|
|
2023-05-27 04:14:56 +08:00
|
|
|
WRITE_ONCE(pcl->next, Z_EROFS_PCLUSTER_TAIL);
|
2018-12-08 00:19:18 +08:00
|
|
|
|
|
|
|
WRITE_ONCE(*submit_qtail, owned_head);
|
2019-07-31 23:57:47 +08:00
|
|
|
WRITE_ONCE(*bypass_qtail, &pcl->next);
|
2018-12-08 00:19:18 +08:00
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
qtail[JQ_BYPASS] = &pcl->next;
|
2018-12-08 00:19:18 +08:00
|
|
|
}
|
|
|
|
|
2022-01-21 17:14:12 +08:00
|
|
|
static void z_erofs_decompressqueue_endio(struct bio *bio)
|
|
|
|
{
|
2023-02-04 17:30:36 +08:00
|
|
|
struct z_erofs_decompressqueue *q = bio->bi_private;
|
2022-01-21 17:14:12 +08:00
|
|
|
blk_status_t err = bio->bi_status;
|
|
|
|
struct bio_vec *bvec;
|
|
|
|
struct bvec_iter_all iter_all;
|
|
|
|
|
|
|
|
bio_for_each_segment_all(bvec, bio, iter_all) {
|
|
|
|
struct page *page = bvec->bv_page;
|
|
|
|
|
|
|
|
DBG_BUGON(PageUptodate(page));
|
|
|
|
DBG_BUGON(z_erofs_page_is_invalidated(page));
|
|
|
|
|
|
|
|
if (erofs_page_is_managed(EROFS_SB(q->sb), page)) {
|
|
|
|
if (!err)
|
|
|
|
SetPageUptodate(page);
|
|
|
|
unlock_page(page);
|
|
|
|
}
|
|
|
|
}
|
2022-07-15 23:41:55 +08:00
|
|
|
if (err)
|
|
|
|
q->eio = true;
|
2023-02-04 17:30:36 +08:00
|
|
|
z_erofs_decompress_kickoff(q, -1);
|
2022-01-21 17:14:12 +08:00
|
|
|
bio_put(bio);
|
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
static void z_erofs_submit_queue(struct z_erofs_decompress_frontend *f,
|
2019-11-08 11:37:33 +08:00
|
|
|
struct z_erofs_decompressqueue *fgq,
|
2023-05-24 14:39:44 +08:00
|
|
|
bool *force_fg, bool readahead)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-07-15 23:41:48 +08:00
|
|
|
struct super_block *sb = f->inode->i_sb;
|
|
|
|
struct address_space *mc = MNGD_MAPPING(EROFS_SB(sb));
|
2019-07-31 23:57:47 +08:00
|
|
|
z_erofs_next_pcluster_t qtail[NR_JOBQUEUES];
|
2019-10-08 20:56:15 +08:00
|
|
|
struct z_erofs_decompressqueue *q[NR_JOBQUEUES];
|
2022-03-02 03:49:50 +08:00
|
|
|
z_erofs_next_pcluster_t owned_head = f->owned_head;
|
2021-10-14 16:10:10 +08:00
|
|
|
/* bio is NULL initially, so no need to initialize last_{index,bdev} */
|
treewide: Remove uninitialized_var() usage
Using uninitialized_var() is dangerous as it papers over real bugs[1]
(or can in the future), and suppresses unrelated compiler warnings
(e.g. "unused variable"). If the compiler thinks it is uninitialized,
either simply initialize the variable or make compiler changes.
In preparation for removing[2] the[3] macro[4], remove all remaining
needless uses with the following script:
git grep '\buninitialized_var\b' | cut -d: -f1 | sort -u | \
xargs perl -pi -e \
's/\buninitialized_var\(([^\)]+)\)/\1/g;
s:\s*/\* (GCC be quiet|to make compiler happy) \*/$::g;'
drivers/video/fbdev/riva/riva_hw.c was manually tweaked to avoid
pathological white-space.
No outstanding warnings were found building allmodconfig with GCC 9.3.0
for x86_64, i386, arm64, arm, powerpc, powerpc64le, s390x, mips, sparc64,
alpha, and m68k.
[1] https://lore.kernel.org/lkml/20200603174714.192027-1-glider@google.com/
[2] https://lore.kernel.org/lkml/CA+55aFw+Vbj0i=1TGqCR5vQkCzWJ0QxK6CernOU6eedsudAixw@mail.gmail.com/
[3] https://lore.kernel.org/lkml/CA+55aFwgbgqhbp1fkxvRKEpzyR5J8n1vKT1VZdz9knmPuXhOeg@mail.gmail.com/
[4] https://lore.kernel.org/lkml/CA+55aFz2500WfbKXAx8s67wrm9=yVJu65TpLgN_ybYNv0VEOKA@mail.gmail.com/
Reviewed-by: Leon Romanovsky <leonro@mellanox.com> # drivers/infiniband and mlx4/mlx5
Acked-by: Jason Gunthorpe <jgg@mellanox.com> # IB
Acked-by: Kalle Valo <kvalo@codeaurora.org> # wireless drivers
Reviewed-by: Chao Yu <yuchao0@huawei.com> # erofs
Signed-off-by: Kees Cook <keescook@chromium.org>
2020-06-04 04:09:38 +08:00
|
|
|
pgoff_t last_index;
|
2021-10-14 16:10:10 +08:00
|
|
|
struct block_device *last_bdev;
|
2020-01-21 14:48:19 +08:00
|
|
|
unsigned int nr_bios = 0;
|
|
|
|
struct bio *bio = NULL;
|
fs: fix leaked psi pressure state
When psi annotations were added to to btrfs compression reads, the psi
state tracking over add_ra_bio_pages and btrfs_submit_compressed_read was
faulty. A pressure state, once entered, is never left. This results in
incorrectly elevated pressure, which triggers OOM kills.
pflags record the *previous* memstall state when we enter a new one. The
code tried to initialize pflags to 1, and then optimize the leave call
when we either didn't enter a memstall, or were already inside a nested
stall. However, there can be multiple PageWorkingset pages in the bio, at
which point it's that path itself that enters repeatedly and overwrites
pflags. This causes us to miss the exit.
Enter the stall only once if needed, then unwind correctly.
erofs has the same problem, fix that up too. And move the memstall exit
past submit_bio() to restore submit accounting originally added by
b8e24a9300b0 ("block: annotate refault stalls from IO submission").
Link: https://lkml.kernel.org/r/Y2UHRqthNUwuIQGS@cmpxchg.org
Fixes: 4088a47e78f9 ("btrfs: add manual PSI accounting for compressed reads")
Fixes: 99486c511f68 ("erofs: add manual PSI accounting for the compressed address space")
Fixes: 118f3663fbc6 ("block: remove PSI accounting from the bio layer")
Link: https://lore.kernel.org/r/d20a0a85-e415-cf78-27f9-77dd7a94bc8d@leemhuis.info/
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Sterba <dsterba@suse.com>
Cc: Gao Xiang <xiang@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-11-04 05:34:31 +08:00
|
|
|
unsigned long pflags;
|
|
|
|
int memstall = 0;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-02-04 17:30:36 +08:00
|
|
|
/*
|
|
|
|
* if managed cache is enabled, bypass jobqueue is needed,
|
|
|
|
* no need to read from device for all pclusters in this queue.
|
|
|
|
*/
|
|
|
|
q[JQ_BYPASS] = jobqueue_init(sb, fgq + JQ_BYPASS, NULL);
|
|
|
|
q[JQ_SUBMIT] = jobqueue_init(sb, fgq + JQ_SUBMIT, force_fg);
|
|
|
|
|
2019-10-08 20:56:15 +08:00
|
|
|
qtail[JQ_BYPASS] = &q[JQ_BYPASS]->head;
|
|
|
|
qtail[JQ_SUBMIT] = &q[JQ_SUBMIT]->head;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
|
|
|
/* by default, all need io submission */
|
2018-12-08 00:19:18 +08:00
|
|
|
q[JQ_SUBMIT]->head = owned_head;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
|
|
|
do {
|
2021-10-14 16:10:10 +08:00
|
|
|
struct erofs_map_dev mdev;
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_pcluster *pcl;
|
2020-01-21 14:48:19 +08:00
|
|
|
pgoff_t cur, end;
|
|
|
|
unsigned int i = 0;
|
|
|
|
bool bypass = true;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-07-31 23:57:47 +08:00
|
|
|
DBG_BUGON(owned_head == Z_EROFS_PCLUSTER_NIL);
|
|
|
|
pcl = container_of(owned_head, struct z_erofs_pcluster, next);
|
2023-05-27 04:14:56 +08:00
|
|
|
owned_head = READ_ONCE(pcl->next);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2021-12-29 07:29:19 +08:00
|
|
|
if (z_erofs_is_inline_pcluster(pcl)) {
|
|
|
|
move_to_bypass_jobqueue(pcl, qtail, owned_head);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-10-14 16:10:10 +08:00
|
|
|
/* no device id here, thus it will always succeed */
|
|
|
|
mdev = (struct erofs_map_dev) {
|
2023-03-13 21:53:08 +08:00
|
|
|
.m_pa = erofs_pos(sb, pcl->obj.index),
|
2021-10-14 16:10:10 +08:00
|
|
|
};
|
|
|
|
(void)erofs_map_dev(sb, &mdev);
|
|
|
|
|
2023-03-13 21:53:08 +08:00
|
|
|
cur = erofs_blknr(sb, mdev.m_pa);
|
2021-04-07 12:39:20 +08:00
|
|
|
end = cur + pcl->pclusterpages;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-01-21 14:48:19 +08:00
|
|
|
do {
|
|
|
|
struct page *page;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
page = pickup_page_for_submission(pcl, i++,
|
|
|
|
&f->pagepool, mc);
|
2020-01-21 14:48:19 +08:00
|
|
|
if (!page)
|
|
|
|
continue;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2021-10-14 16:10:10 +08:00
|
|
|
if (bio && (cur != last_index + 1 ||
|
|
|
|
last_bdev != mdev.m_bdev)) {
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
submit_bio_retry:
|
2020-01-21 14:48:19 +08:00
|
|
|
submit_bio(bio);
|
fs: fix leaked psi pressure state
When psi annotations were added to to btrfs compression reads, the psi
state tracking over add_ra_bio_pages and btrfs_submit_compressed_read was
faulty. A pressure state, once entered, is never left. This results in
incorrectly elevated pressure, which triggers OOM kills.
pflags record the *previous* memstall state when we enter a new one. The
code tried to initialize pflags to 1, and then optimize the leave call
when we either didn't enter a memstall, or were already inside a nested
stall. However, there can be multiple PageWorkingset pages in the bio, at
which point it's that path itself that enters repeatedly and overwrites
pflags. This causes us to miss the exit.
Enter the stall only once if needed, then unwind correctly.
erofs has the same problem, fix that up too. And move the memstall exit
past submit_bio() to restore submit accounting originally added by
b8e24a9300b0 ("block: annotate refault stalls from IO submission").
Link: https://lkml.kernel.org/r/Y2UHRqthNUwuIQGS@cmpxchg.org
Fixes: 4088a47e78f9 ("btrfs: add manual PSI accounting for compressed reads")
Fixes: 99486c511f68 ("erofs: add manual PSI accounting for the compressed address space")
Fixes: 118f3663fbc6 ("block: remove PSI accounting from the bio layer")
Link: https://lore.kernel.org/r/d20a0a85-e415-cf78-27f9-77dd7a94bc8d@leemhuis.info/
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Sterba <dsterba@suse.com>
Cc: Gao Xiang <xiang@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-11-04 05:34:31 +08:00
|
|
|
if (memstall) {
|
|
|
|
psi_memstall_leave(&pflags);
|
|
|
|
memstall = 0;
|
|
|
|
}
|
2020-01-21 14:48:19 +08:00
|
|
|
bio = NULL;
|
|
|
|
}
|
2019-09-04 10:09:02 +08:00
|
|
|
|
fs: fix leaked psi pressure state
When psi annotations were added to to btrfs compression reads, the psi
state tracking over add_ra_bio_pages and btrfs_submit_compressed_read was
faulty. A pressure state, once entered, is never left. This results in
incorrectly elevated pressure, which triggers OOM kills.
pflags record the *previous* memstall state when we enter a new one. The
code tried to initialize pflags to 1, and then optimize the leave call
when we either didn't enter a memstall, or were already inside a nested
stall. However, there can be multiple PageWorkingset pages in the bio, at
which point it's that path itself that enters repeatedly and overwrites
pflags. This causes us to miss the exit.
Enter the stall only once if needed, then unwind correctly.
erofs has the same problem, fix that up too. And move the memstall exit
past submit_bio() to restore submit accounting originally added by
b8e24a9300b0 ("block: annotate refault stalls from IO submission").
Link: https://lkml.kernel.org/r/Y2UHRqthNUwuIQGS@cmpxchg.org
Fixes: 4088a47e78f9 ("btrfs: add manual PSI accounting for compressed reads")
Fixes: 99486c511f68 ("erofs: add manual PSI accounting for the compressed address space")
Fixes: 118f3663fbc6 ("block: remove PSI accounting from the bio layer")
Link: https://lore.kernel.org/r/d20a0a85-e415-cf78-27f9-77dd7a94bc8d@leemhuis.info/
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Sterba <dsterba@suse.com>
Cc: Gao Xiang <xiang@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-11-04 05:34:31 +08:00
|
|
|
if (unlikely(PageWorkingset(page)) && !memstall) {
|
2022-09-15 17:41:59 +08:00
|
|
|
psi_memstall_enter(&pflags);
|
fs: fix leaked psi pressure state
When psi annotations were added to to btrfs compression reads, the psi
state tracking over add_ra_bio_pages and btrfs_submit_compressed_read was
faulty. A pressure state, once entered, is never left. This results in
incorrectly elevated pressure, which triggers OOM kills.
pflags record the *previous* memstall state when we enter a new one. The
code tried to initialize pflags to 1, and then optimize the leave call
when we either didn't enter a memstall, or were already inside a nested
stall. However, there can be multiple PageWorkingset pages in the bio, at
which point it's that path itself that enters repeatedly and overwrites
pflags. This causes us to miss the exit.
Enter the stall only once if needed, then unwind correctly.
erofs has the same problem, fix that up too. And move the memstall exit
past submit_bio() to restore submit accounting originally added by
b8e24a9300b0 ("block: annotate refault stalls from IO submission").
Link: https://lkml.kernel.org/r/Y2UHRqthNUwuIQGS@cmpxchg.org
Fixes: 4088a47e78f9 ("btrfs: add manual PSI accounting for compressed reads")
Fixes: 99486c511f68 ("erofs: add manual PSI accounting for the compressed address space")
Fixes: 118f3663fbc6 ("block: remove PSI accounting from the bio layer")
Link: https://lore.kernel.org/r/d20a0a85-e415-cf78-27f9-77dd7a94bc8d@leemhuis.info/
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Sterba <dsterba@suse.com>
Cc: Gao Xiang <xiang@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-11-04 05:34:31 +08:00
|
|
|
memstall = 1;
|
|
|
|
}
|
2022-09-15 17:41:59 +08:00
|
|
|
|
2020-01-21 14:48:19 +08:00
|
|
|
if (!bio) {
|
2022-01-24 17:11:05 +08:00
|
|
|
bio = bio_alloc(mdev.m_bdev, BIO_MAX_VECS,
|
|
|
|
REQ_OP_READ, GFP_NOIO);
|
2020-01-21 14:48:19 +08:00
|
|
|
bio->bi_end_io = z_erofs_decompressqueue_endio;
|
2021-10-14 16:10:10 +08:00
|
|
|
|
|
|
|
last_bdev = mdev.m_bdev;
|
2020-01-21 14:48:19 +08:00
|
|
|
bio->bi_iter.bi_sector = (sector_t)cur <<
|
2023-03-13 21:53:08 +08:00
|
|
|
(sb->s_blocksize_bits - 9);
|
2023-02-04 17:30:36 +08:00
|
|
|
bio->bi_private = q[JQ_SUBMIT];
|
2023-05-24 14:39:44 +08:00
|
|
|
if (readahead)
|
2020-09-19 15:27:30 +08:00
|
|
|
bio->bi_opf |= REQ_RAHEAD;
|
2020-01-21 14:48:19 +08:00
|
|
|
++nr_bios;
|
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-09-19 15:27:28 +08:00
|
|
|
if (bio_add_page(bio, page, PAGE_SIZE, 0) < PAGE_SIZE)
|
2020-01-21 14:48:19 +08:00
|
|
|
goto submit_bio_retry;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-01-21 14:48:19 +08:00
|
|
|
last_index = cur;
|
|
|
|
bypass = false;
|
|
|
|
} while (++cur < end);
|
2018-07-26 20:22:07 +08:00
|
|
|
|
2020-01-21 14:48:19 +08:00
|
|
|
if (!bypass)
|
2019-07-31 23:57:47 +08:00
|
|
|
qtail[JQ_SUBMIT] = &pcl->next;
|
2018-12-08 00:19:18 +08:00
|
|
|
else
|
2019-07-31 23:57:47 +08:00
|
|
|
move_to_bypass_jobqueue(pcl, qtail, owned_head);
|
|
|
|
} while (owned_head != Z_EROFS_PCLUSTER_TAIL);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-09-15 17:41:59 +08:00
|
|
|
if (bio) {
|
2019-09-04 10:09:04 +08:00
|
|
|
submit_bio(bio);
|
fs: fix leaked psi pressure state
When psi annotations were added to to btrfs compression reads, the psi
state tracking over add_ra_bio_pages and btrfs_submit_compressed_read was
faulty. A pressure state, once entered, is never left. This results in
incorrectly elevated pressure, which triggers OOM kills.
pflags record the *previous* memstall state when we enter a new one. The
code tried to initialize pflags to 1, and then optimize the leave call
when we either didn't enter a memstall, or were already inside a nested
stall. However, there can be multiple PageWorkingset pages in the bio, at
which point it's that path itself that enters repeatedly and overwrites
pflags. This causes us to miss the exit.
Enter the stall only once if needed, then unwind correctly.
erofs has the same problem, fix that up too. And move the memstall exit
past submit_bio() to restore submit accounting originally added by
b8e24a9300b0 ("block: annotate refault stalls from IO submission").
Link: https://lkml.kernel.org/r/Y2UHRqthNUwuIQGS@cmpxchg.org
Fixes: 4088a47e78f9 ("btrfs: add manual PSI accounting for compressed reads")
Fixes: 99486c511f68 ("erofs: add manual PSI accounting for the compressed address space")
Fixes: 118f3663fbc6 ("block: remove PSI accounting from the bio layer")
Link: https://lore.kernel.org/r/d20a0a85-e415-cf78-27f9-77dd7a94bc8d@leemhuis.info/
Signed-off-by: Johannes Weiner <hannes@cmpxchg.org>
Reported-by: Thorsten Leemhuis <linux@leemhuis.info>
Tested-by: Thorsten Leemhuis <linux@leemhuis.info>
Cc: Chao Yu <chao@kernel.org>
Cc: Chris Mason <clm@fb.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: David Sterba <dsterba@suse.com>
Cc: Gao Xiang <xiang@kernel.org>
Cc: Jens Axboe <axboe@kernel.dk>
Cc: Josef Bacik <josef@toxicpanda.com>
Cc: Suren Baghdasaryan <surenb@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
2022-11-04 05:34:31 +08:00
|
|
|
if (memstall)
|
|
|
|
psi_memstall_leave(&pflags);
|
2022-09-15 17:41:59 +08:00
|
|
|
}
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-01-21 14:47:47 +08:00
|
|
|
/*
|
|
|
|
* although background is preferred, no one is pending for submission.
|
2023-02-08 17:33:22 +08:00
|
|
|
* don't issue decompression but drop it directly instead.
|
2020-01-21 14:47:47 +08:00
|
|
|
*/
|
|
|
|
if (!*force_fg && !nr_bios) {
|
|
|
|
kvfree(q[JQ_SUBMIT]);
|
2020-01-21 14:48:19 +08:00
|
|
|
return;
|
2020-01-21 14:47:47 +08:00
|
|
|
}
|
2023-02-04 17:30:36 +08:00
|
|
|
z_erofs_decompress_kickoff(q[JQ_SUBMIT], nr_bios);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2022-07-15 23:41:48 +08:00
|
|
|
static void z_erofs_runqueue(struct z_erofs_decompress_frontend *f,
|
2023-05-27 04:14:55 +08:00
|
|
|
bool force_fg, bool ra)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2019-10-08 20:56:15 +08:00
|
|
|
struct z_erofs_decompressqueue io[NR_JOBQUEUES];
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-03-02 03:49:50 +08:00
|
|
|
if (f->owned_head == Z_EROFS_PCLUSTER_TAIL)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
return;
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_submit_queue(f, io, &force_fg, ra);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-11-08 11:37:33 +08:00
|
|
|
/* handle bypass queue (no i/o pclusters) immediately */
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_decompress_queue(&io[JQ_BYPASS], &f->pagepool);
|
2019-07-31 23:57:49 +08:00
|
|
|
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
if (!force_fg)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* wait until all bios are completed */
|
2022-04-01 19:55:27 +08:00
|
|
|
wait_for_completion_io(&io[JQ_SUBMIT].u.done);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-11-08 11:37:33 +08:00
|
|
|
/* handle synchronous decompress queue in the caller context */
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_decompress_queue(&io[JQ_SUBMIT], &f->pagepool);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2021-10-09 04:08:39 +08:00
|
|
|
/*
|
|
|
|
* Since partial uptodate is still unimplemented for now, we have to use
|
|
|
|
* approximate readmore strategies as a start.
|
|
|
|
*/
|
|
|
|
static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f,
|
2023-05-27 04:14:55 +08:00
|
|
|
struct readahead_control *rac, bool backmost)
|
2021-10-09 04:08:39 +08:00
|
|
|
{
|
|
|
|
struct inode *inode = f->inode;
|
|
|
|
struct erofs_map_blocks *map = &f->map;
|
2023-05-25 15:26:05 +08:00
|
|
|
erofs_off_t cur, end, headoffset = f->headoffset;
|
2021-10-09 04:08:39 +08:00
|
|
|
int err;
|
|
|
|
|
|
|
|
if (backmost) {
|
2023-05-25 15:26:05 +08:00
|
|
|
if (rac)
|
|
|
|
end = headoffset + readahead_length(rac) - 1;
|
|
|
|
else
|
|
|
|
end = headoffset + PAGE_SIZE - 1;
|
2021-10-09 04:08:39 +08:00
|
|
|
map->m_la = end;
|
2021-10-11 05:31:45 +08:00
|
|
|
err = z_erofs_map_blocks_iter(inode, map,
|
|
|
|
EROFS_GET_BLOCKS_READMORE);
|
2021-10-09 04:08:39 +08:00
|
|
|
if (err)
|
|
|
|
return;
|
|
|
|
|
2023-05-25 15:26:05 +08:00
|
|
|
/* expand ra for the trailing edge if readahead */
|
2021-10-09 04:08:39 +08:00
|
|
|
if (rac) {
|
|
|
|
cur = round_up(map->m_la + map->m_llen, PAGE_SIZE);
|
2023-05-25 15:26:05 +08:00
|
|
|
readahead_expand(rac, headoffset, cur - headoffset);
|
2021-10-09 04:08:39 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
end = round_up(end, PAGE_SIZE);
|
|
|
|
} else {
|
|
|
|
end = round_up(map->m_la, PAGE_SIZE);
|
|
|
|
|
|
|
|
if (!map->m_llen)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cur = map->m_la + map->m_llen - 1;
|
2023-07-10 12:25:31 +08:00
|
|
|
while ((cur >= end) && (cur < i_size_read(inode))) {
|
2021-10-09 04:08:39 +08:00
|
|
|
pgoff_t index = cur >> PAGE_SHIFT;
|
|
|
|
struct page *page;
|
|
|
|
|
|
|
|
page = erofs_grab_cache_page_nowait(inode->i_mapping, index);
|
2022-05-29 13:54:25 +08:00
|
|
|
if (page) {
|
|
|
|
if (PageUptodate(page)) {
|
|
|
|
unlock_page(page);
|
|
|
|
} else {
|
2023-05-27 04:14:55 +08:00
|
|
|
err = z_erofs_do_read_page(f, page);
|
2022-05-29 13:54:25 +08:00
|
|
|
if (err)
|
|
|
|
erofs_err(inode->i_sb,
|
|
|
|
"readmore error at page %lu @ nid %llu",
|
|
|
|
index, EROFS_I(inode)->nid);
|
|
|
|
}
|
2021-10-09 04:08:39 +08:00
|
|
|
put_page(page);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cur < PAGE_SIZE)
|
|
|
|
break;
|
|
|
|
cur = (index << PAGE_SHIFT) - 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-29 23:12:16 +08:00
|
|
|
static int z_erofs_read_folio(struct file *file, struct folio *folio)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2022-04-29 23:12:16 +08:00
|
|
|
struct page *page = &folio->page;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
struct inode *const inode = page->mapping->host;
|
2021-12-06 22:35:52 +08:00
|
|
|
struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
int err;
|
|
|
|
|
2018-11-23 01:15:58 +08:00
|
|
|
trace_erofs_readpage(page, false);
|
2018-11-23 01:21:49 +08:00
|
|
|
f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT;
|
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_pcluster_readmore(&f, NULL, true);
|
|
|
|
err = z_erofs_do_read_page(&f, page);
|
|
|
|
z_erofs_pcluster_readmore(&f, NULL, false);
|
2022-03-02 03:49:50 +08:00
|
|
|
(void)z_erofs_collector_end(&f);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2019-08-19 18:34:21 +08:00
|
|
|
/* if some compressed cluster ready, need submit them anyway */
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_runqueue(&f, z_erofs_is_sync_decompress(sbi, 0), false);
|
2019-08-19 18:34:21 +08:00
|
|
|
|
|
|
|
if (err)
|
2019-09-04 10:09:09 +08:00
|
|
|
erofs_err(inode->i_sb, "failed to read, err [%d]", err);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2022-01-02 12:00:17 +08:00
|
|
|
erofs_put_metabuf(&f.map.buf);
|
2023-05-27 04:14:55 +08:00
|
|
|
erofs_release_pages(&f.pagepool);
|
2019-08-19 18:34:21 +08:00
|
|
|
return err;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2020-06-02 12:47:13 +08:00
|
|
|
static void z_erofs_readahead(struct readahead_control *rac)
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
{
|
2020-06-02 12:47:13 +08:00
|
|
|
struct inode *const inode = rac->mapping->host;
|
2018-09-20 00:06:56 +08:00
|
|
|
struct erofs_sb_info *const sbi = EROFS_I_SB(inode);
|
2019-07-31 23:57:47 +08:00
|
|
|
struct z_erofs_decompress_frontend f = DECOMPRESS_FRONTEND_INIT(inode);
|
2023-05-27 04:14:55 +08:00
|
|
|
struct page *head = NULL, *page;
|
2021-10-09 04:08:39 +08:00
|
|
|
unsigned int nr_pages;
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2020-06-02 12:47:13 +08:00
|
|
|
f.headoffset = readahead_pos(rac);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_pcluster_readmore(&f, rac, true);
|
2021-10-09 04:08:39 +08:00
|
|
|
nr_pages = readahead_count(rac);
|
|
|
|
trace_erofs_readpages(inode, readahead_index(rac), nr_pages, false);
|
2018-11-23 01:21:48 +08:00
|
|
|
|
2021-10-09 04:08:39 +08:00
|
|
|
while ((page = readahead_page(rac))) {
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
set_page_private(page, (unsigned long)head);
|
|
|
|
head = page;
|
|
|
|
}
|
|
|
|
|
2018-11-13 04:43:57 +08:00
|
|
|
while (head) {
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
struct page *page = head;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
/* traversal in reverse order */
|
|
|
|
head = (void *)page_private(page);
|
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
err = z_erofs_do_read_page(&f, page);
|
2019-09-04 10:08:56 +08:00
|
|
|
if (err)
|
2019-09-04 10:09:09 +08:00
|
|
|
erofs_err(inode->i_sb,
|
|
|
|
"readahead error at page %lu @ nid %llu",
|
|
|
|
page->index, EROFS_I(inode)->nid);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
put_page(page);
|
|
|
|
}
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_pcluster_readmore(&f, rac, false);
|
2022-03-02 03:49:50 +08:00
|
|
|
(void)z_erofs_collector_end(&f);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
|
2023-05-27 04:14:55 +08:00
|
|
|
z_erofs_runqueue(&f, z_erofs_is_sync_decompress(sbi, nr_pages), true);
|
2022-01-02 12:00:17 +08:00
|
|
|
erofs_put_metabuf(&f.map.buf);
|
2023-05-27 04:14:55 +08:00
|
|
|
erofs_release_pages(&f.pagepool);
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
}
|
|
|
|
|
2019-11-08 11:37:33 +08:00
|
|
|
const struct address_space_operations z_erofs_aops = {
|
2022-04-29 23:12:16 +08:00
|
|
|
.read_folio = z_erofs_read_folio,
|
2020-06-02 12:47:13 +08:00
|
|
|
.readahead = z_erofs_readahead,
|
staging: erofs: introduce VLE decompression support
This patch introduces the basic in-place VLE decompression
implementation for the erofs file system.
Compared with fixed-sized input compression, it implements
what we call 'the variable-length extent compression' which
specifies the same output size for each compression block
to make the full use of IO bandwidth (which means almost
all data from block device can be directly used for decomp-
ression), improve the real (rather than just via data caching,
which costs more memory) random read and keep the relatively
lower compression ratios (it saves more storage space than
fixed-sized input compression which is also configured with
the same input block size), as illustrated below:
|--- variable-length extent ---|------ VLE ------|--- VLE ---|
/> clusterofs /> clusterofs /> clusterofs /> clusterofs
++---|-------++-----------++---------|-++-----------++-|---------++-|
...|| | || || | || || | || | ... original data
++---|-------++-----------++---------|-++-----------++-|---------++-|
++->cluster<-++->cluster<-++->cluster<-++->cluster<-++->cluster<-++
size size size size size
\ / / /
\ / / /
\ / / /
++-----------++-----------++-----------++
... || || || || ... compressed clusters
++-----------++-----------++-----------++
++->cluster<-++->cluster<-++->cluster<-++
size size size
The main point of 'in-place' refers to the decompression mode:
Instead of allocating independent compressed pages and data
structures, it reuses the allocated file cache pages at most
to store its compressed data and the corresponding pagevec in
a time-sharing approach by default, which will be useful for
low memory scenario.
In the end, unlike the other filesystems with (de)compression
support using a relatively large compression block size, which
reads and decompresses >= 128KB at once, and gains a more
good-looking random read (In fact it collects small random reads
into large sequential reads and caches all decompressed data
in memory, but it is unacceptable especially for embedded devices
with limited memory, and it is not the real random read), we
select a universal small-sized 4KB compressed cluster, which is
the smallest page size for most architectures, and all compressed
clusters can be read and decompressed independently, which ensures
random read number for all use cases.
Signed-off-by: Gao Xiang <gaoxiang25@huawei.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2018-07-26 20:22:06 +08:00
|
|
|
};
|