Commit 152a333a authored by Gao Xiang's avatar Gao Xiang Committed by Greg Kroah-Hartman

staging: erofs: add compacted compression indexes support

This patch aims at compacted compression indexes:
 1) cleanup z_erofs_map_blocks_iter and move into zmap.c;
 2) add compacted 4/2B decoding support.

On kirin980 platform, sequential read is increased about
6% (725MiB/s -> 770MiB/s) on enwik9 dataset if compacted 2B
feature is enabled.
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarGao Xiang <gaoxiang25@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ec8c2442
......@@ -9,5 +9,5 @@ obj-$(CONFIG_EROFS_FS) += erofs.o
ccflags-y += -I $(srctree)/$(src)/include
erofs-objs := super.o inode.o data.o namei.o dir.o utils.o
erofs-$(CONFIG_EROFS_FS_XATTR) += xattr.o
erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o unzip_vle_lz4.o
erofs-$(CONFIG_EROFS_FS_ZIP) += unzip_vle.o unzip_vle_lz4.o zmap.o
......@@ -210,12 +210,7 @@ static int fill_inode(struct inode *inode, int isdir)
}
if (is_inode_layout_compression(inode)) {
#ifdef CONFIG_EROFS_FS_ZIP
inode->i_mapping->a_ops =
&z_erofs_vle_normalaccess_aops;
#else
err = -ENOTSUPP;
#endif
err = z_erofs_fill_inode(inode);
goto out_unlock;
}
......
......@@ -339,9 +339,11 @@ static inline erofs_off_t iloc(struct erofs_sb_info *sbi, erofs_nid_t nid)
/* atomic flag definitions */
#define EROFS_V_EA_INITED_BIT 0
#define EROFS_V_Z_INITED_BIT 1
/* bitlock definitions (arranged in reverse order) */
#define EROFS_V_BL_XATTR_BIT (BITS_PER_LONG - 1)
#define EROFS_V_BL_Z_BIT (BITS_PER_LONG - 2)
struct erofs_vnode {
erofs_nid_t nid;
......@@ -356,8 +358,17 @@ struct erofs_vnode {
unsigned xattr_shared_count;
unsigned *xattr_shared_xattrs;
erofs_blk_t raw_blkaddr;
union {
erofs_blk_t raw_blkaddr;
#ifdef CONFIG_EROFS_FS_ZIP
struct {
unsigned short z_advise;
unsigned char z_algorithmtype[2];
unsigned char z_logical_clusterbits;
unsigned char z_physical_clusterbits[2];
};
#endif
};
/* the corresponding vfs inode */
struct inode vfs_inode;
};
......@@ -447,11 +458,14 @@ struct erofs_map_blocks {
/* Flags used by erofs_map_blocks() */
#define EROFS_GET_BLOCKS_RAW 0x0001
/* zmap.c */
#ifdef CONFIG_EROFS_FS_ZIP
int z_erofs_fill_inode(struct inode *inode);
int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
int flags);
#else
static inline int z_erofs_fill_inode(struct inode *inode) { return -ENOTSUPP; }
static inline int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
int flags)
......
......@@ -1600,289 +1600,3 @@ const struct address_space_operations z_erofs_vle_normalaccess_aops = {
.readpages = z_erofs_vle_normalaccess_readpages,
};
/*
* Variable-sized Logical Extent (Fixed Physical Cluster) Compression Mode
* ---
* VLE compression mode attempts to compress a number of logical data into
* a physical cluster with a fixed size.
* VLE compression mode uses "struct z_erofs_vle_decompressed_index".
*/
#define __vle_cluster_advise(x, bit, bits) \
((le16_to_cpu(x) >> (bit)) & ((1 << (bits)) - 1))
#define __vle_cluster_type(advise) __vle_cluster_advise(advise, \
Z_EROFS_VLE_DI_CLUSTER_TYPE_BIT, Z_EROFS_VLE_DI_CLUSTER_TYPE_BITS)
#define vle_cluster_type(di) \
__vle_cluster_type((di)->di_advise)
static int
vle_decompressed_index_clusterofs(unsigned int *clusterofs,
unsigned int clustersize,
struct z_erofs_vle_decompressed_index *di)
{
switch (vle_cluster_type(di)) {
case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
*clusterofs = clustersize;
break;
case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
*clusterofs = le16_to_cpu(di->di_clusterofs);
break;
default:
DBG_BUGON(1);
return -EIO;
}
return 0;
}
static inline erofs_blk_t
vle_extent_blkaddr(struct inode *inode, pgoff_t index)
{
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
struct erofs_vnode *vi = EROFS_V(inode);
unsigned int ofs = Z_EROFS_VLE_LEGACY_INDEX_ALIGN(vi->inode_isize +
vi->xattr_isize) +
index * sizeof(struct z_erofs_vle_decompressed_index);
return erofs_blknr(iloc(sbi, vi->nid) + ofs);
}
static inline unsigned int
vle_extent_blkoff(struct inode *inode, pgoff_t index)
{
struct erofs_sb_info *sbi = EROFS_I_SB(inode);
struct erofs_vnode *vi = EROFS_V(inode);
unsigned int ofs = Z_EROFS_VLE_LEGACY_INDEX_ALIGN(vi->inode_isize +
vi->xattr_isize) +
index * sizeof(struct z_erofs_vle_decompressed_index);
return erofs_blkoff(iloc(sbi, vi->nid) + ofs);
}
struct vle_map_blocks_iter_ctx {
struct inode *inode;
struct super_block *sb;
unsigned int clusterbits;
struct page **mpage_ret;
void **kaddr_ret;
};
static int
vle_get_logical_extent_head(const struct vle_map_blocks_iter_ctx *ctx,
unsigned int lcn, /* logical cluster number */
unsigned long long *ofs,
erofs_blk_t *pblk,
unsigned int *flags)
{
const unsigned int clustersize = 1 << ctx->clusterbits;
const erofs_blk_t mblk = vle_extent_blkaddr(ctx->inode, lcn);
struct page *mpage = *ctx->mpage_ret; /* extent metapage */
struct z_erofs_vle_decompressed_index *di;
unsigned int cluster_type, delta0;
if (mpage->index != mblk) {
kunmap_atomic(*ctx->kaddr_ret);
unlock_page(mpage);
put_page(mpage);
mpage = erofs_get_meta_page(ctx->sb, mblk, false);
if (IS_ERR(mpage)) {
*ctx->mpage_ret = NULL;
return PTR_ERR(mpage);
}
*ctx->mpage_ret = mpage;
*ctx->kaddr_ret = kmap_atomic(mpage);
}
di = *ctx->kaddr_ret + vle_extent_blkoff(ctx->inode, lcn);
cluster_type = vle_cluster_type(di);
switch (cluster_type) {
case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
delta0 = le16_to_cpu(di->di_u.delta[0]);
if (unlikely(!delta0 || delta0 > lcn)) {
errln("invalid NONHEAD dl0 %u at lcn %u of nid %llu",
delta0, lcn, EROFS_V(ctx->inode)->nid);
DBG_BUGON(1);
return -EIO;
}
return vle_get_logical_extent_head(ctx,
lcn - delta0, ofs, pblk, flags);
case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
*flags ^= EROFS_MAP_ZIPPED;
/* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
/* clustersize should be a power of two */
*ofs = ((u64)lcn << ctx->clusterbits) +
(le16_to_cpu(di->di_clusterofs) & (clustersize - 1));
*pblk = le32_to_cpu(di->di_u.blkaddr);
break;
default:
errln("unknown cluster type %u at lcn %u of nid %llu",
cluster_type, lcn, EROFS_V(ctx->inode)->nid);
DBG_BUGON(1);
return -EIO;
}
return 0;
}
int z_erofs_map_blocks_iter(struct inode *inode,
struct erofs_map_blocks *map,
int flags)
{
void *kaddr;
const struct vle_map_blocks_iter_ctx ctx = {
.inode = inode,
.sb = inode->i_sb,
.clusterbits = EROFS_I_SB(inode)->clusterbits,
.mpage_ret = &map->mpage,
.kaddr_ret = &kaddr
};
const unsigned int clustersize = 1 << ctx.clusterbits;
/* if both m_(l,p)len are 0, regularize l_lblk, l_lofs, etc... */
const bool initial = !map->m_llen;
/* logicial extent (start, end) offset */
unsigned long long ofs, end;
unsigned int lcn;
u32 ofs_rem;
/* initialize `pblk' to keep gcc from printing foolish warnings */
erofs_blk_t mblk, pblk = 0;
struct page *mpage = map->mpage;
struct z_erofs_vle_decompressed_index *di;
unsigned int cluster_type, logical_cluster_ofs;
int err = 0;
trace_z_erofs_map_blocks_iter_enter(inode, map, flags);
/* when trying to read beyond EOF, leave it unmapped */
if (unlikely(map->m_la >= inode->i_size)) {
DBG_BUGON(!initial);
map->m_llen = map->m_la + 1 - inode->i_size;
map->m_la = inode->i_size;
map->m_flags = 0;
goto out;
}
debugln("%s, m_la %llu m_llen %llu --- start", __func__,
map->m_la, map->m_llen);
ofs = map->m_la + map->m_llen;
/* clustersize should be power of two */
lcn = ofs >> ctx.clusterbits;
ofs_rem = ofs & (clustersize - 1);
mblk = vle_extent_blkaddr(inode, lcn);
if (!mpage || mpage->index != mblk) {
if (mpage)
put_page(mpage);
mpage = erofs_get_meta_page(ctx.sb, mblk, false);
if (IS_ERR(mpage)) {
err = PTR_ERR(mpage);
goto out;
}
map->mpage = mpage;
} else {
lock_page(mpage);
DBG_BUGON(!PageUptodate(mpage));
}
kaddr = kmap_atomic(mpage);
di = kaddr + vle_extent_blkoff(inode, lcn);
debugln("%s, lcn %u mblk %u e_blkoff %u", __func__, lcn,
mblk, vle_extent_blkoff(inode, lcn));
err = vle_decompressed_index_clusterofs(&logical_cluster_ofs,
clustersize, di);
if (unlikely(err))
goto unmap_out;
if (!initial) {
/* [walking mode] 'map' has been already initialized */
map->m_llen += logical_cluster_ofs;
goto unmap_out;
}
/* by default, compressed */
map->m_flags |= EROFS_MAP_ZIPPED;
end = ((u64)lcn + 1) * clustersize;
cluster_type = vle_cluster_type(di);
switch (cluster_type) {
case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
if (ofs_rem >= logical_cluster_ofs)
map->m_flags ^= EROFS_MAP_ZIPPED;
/* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
if (ofs_rem == logical_cluster_ofs) {
pblk = le32_to_cpu(di->di_u.blkaddr);
goto exact_hitted;
}
if (ofs_rem > logical_cluster_ofs) {
ofs = (u64)lcn * clustersize | logical_cluster_ofs;
pblk = le32_to_cpu(di->di_u.blkaddr);
break;
}
/* logical cluster number should be >= 1 */
if (unlikely(!lcn)) {
errln("invalid logical cluster 0 at nid %llu",
EROFS_V(inode)->nid);
err = -EIO;
goto unmap_out;
}
end = ((u64)lcn-- * clustersize) | logical_cluster_ofs;
/* fallthrough */
case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
/* get the correspoinding first chunk */
err = vle_get_logical_extent_head(&ctx, lcn, &ofs,
&pblk, &map->m_flags);
mpage = map->mpage;
if (unlikely(err)) {
if (mpage)
goto unmap_out;
goto out;
}
break;
default:
errln("unknown cluster type %u at offset %llu of nid %llu",
cluster_type, ofs, EROFS_V(inode)->nid);
err = -EIO;
goto unmap_out;
}
map->m_la = ofs;
exact_hitted:
map->m_llen = end - ofs;
map->m_plen = clustersize;
map->m_pa = blknr_to_addr(pblk);
map->m_flags |= EROFS_MAP_MAPPED;
unmap_out:
kunmap_atomic(kaddr);
unlock_page(mpage);
out:
debugln("%s, m_la %llu m_pa %llu m_llen %llu m_plen %llu m_flags 0%o",
__func__, map->m_la, map->m_pa,
map->m_llen, map->m_plen, map->m_flags);
trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err);
/* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */
DBG_BUGON(err < 0 && err != -ENOMEM);
return err;
}
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment