[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <f3437906-f983-65f9-8471-35f94b57d889@kernel.org>
Date: Mon, 16 Aug 2021 23:38:03 +0800
From: Chao Yu <chao@...nel.org>
To: Gao Xiang <hsiangkao@...ux.alibaba.com>,
linux-erofs@...ts.ozlabs.org
Cc: LKML <linux-kernel@...r.kernel.org>,
Huang Jianan <huangjianan@...o.com>,
Lasse Collin <lasse.collin@...aani.org>,
nl6720 <nl6720@...il.com>
Subject: Re: [PATCH 1/2] erofs: add support for the full decompressed length
On 2021/8/13 13:29, Gao Xiang wrote:
> Previously, there is no need to get the full decompressed length since
> EROFS supports partial decompression. However for some other cases
> such as fiemap, the full decompressed length is necessary for iomap to
> make it work properly.
>
> This patch adds a way to get the full decompressed length. Note that
> it takes more metadata overhead and it'd be avoided if possible in the
> performance sensitive scenario.
>
> Signed-off-by: Gao Xiang <hsiangkao@...ux.alibaba.com>
> ---
> fs/erofs/internal.h | 5 +++
> fs/erofs/zmap.c | 93 +++++++++++++++++++++++++++++++++++++++++----
> 2 files changed, 90 insertions(+), 8 deletions(-)
>
> diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h
> index 25b094085ca6..2a05b09e1c06 100644
> --- a/fs/erofs/internal.h
> +++ b/fs/erofs/internal.h
> @@ -356,6 +356,11 @@ struct erofs_map_blocks {
>
> /* Flags used by erofs_map_blocks_flatmode() */
> #define EROFS_GET_BLOCKS_RAW 0x0001
> +/*
> + * Used to get the exact decompressed length, e.g. fiemap (consider lookback
> + * approach instead if possible since it's quite metadata expensive.)
> + */
> +#define EROFS_GET_BLOCKS_FIEMAP 0x0002
>
> /* zmap.c */
> #ifdef CONFIG_EROFS_FS_ZIP
> diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c
> index f68aea4baed7..12256ef12819 100644
> --- a/fs/erofs/zmap.c
> +++ b/fs/erofs/zmap.c
> @@ -212,9 +212,32 @@ static unsigned int decode_compactedbits(unsigned int lobits,
> return lo;
> }
>
> +static int get_compacted_la_distance(unsigned int lclusterbits,
> + unsigned int encodebits,
> + unsigned int vcnt, u8 *in, int i)
> +{
> + const unsigned int lomask = (1 << lclusterbits) - 1;
> + unsigned int lo, d1 = 0;
> + u8 type;
> +
> + for (; i < vcnt; ++i) {
for (di = 0; i < vcnt; ++i, ++d1)
> + lo = decode_compactedbits(lclusterbits, lomask,
> + in, encodebits * i, &type);
> +
> + if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
> + return d1;
[1]
> + ++d1;
> + }
> +
> + /* vcnt - 1 (Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) item */
> + if (!(lo & Z_EROFS_VLE_DI_D0_CBLKCNT))
> + d1 += lo - 1;
> + return d1;
> +}
> +
> static int unpack_compacted_index(struct z_erofs_maprecorder *m,
> unsigned int amortizedshift,
> - unsigned int eofs)
> + unsigned int eofs, bool lookahead)
> {
> struct erofs_inode *const vi = EROFS_I(m->inode);
> const unsigned int lclusterbits = vi->z_logical_clusterbits;
> @@ -243,6 +266,11 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
> m->type = type;
> if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
> m->clusterofs = 1 << lclusterbits;
> +
> + /* figure out lookahead_distance: delta[1] if needed */
> + if (lookahead)
> + m->delta[1] = get_compacted_la_distance(lclusterbits,
> + encodebits, vcnt, in, i);
> if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
> if (!big_pcluster) {
> DBG_BUGON(1);
> @@ -313,7 +341,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
> }
>
> static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
> - unsigned long lcn)
> + unsigned long lcn, bool lookahead)
> {
> struct inode *const inode = m->inode;
> struct erofs_inode *const vi = EROFS_I(inode);
> @@ -364,11 +392,12 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
> err = z_erofs_reload_indexes(m, erofs_blknr(pos));
> if (err)
> return err;
> - return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
> + return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos),
> + lookahead);
> }
>
> static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
> - unsigned int lcn)
> + unsigned int lcn, bool lookahead)
> {
> const unsigned int datamode = EROFS_I(m->inode)->datalayout;
>
> @@ -376,7 +405,7 @@ static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
> return legacy_load_cluster_from_disk(m, lcn);
>
> if (datamode == EROFS_INODE_FLAT_COMPRESSION)
> - return compacted_load_cluster_from_disk(m, lcn);
> + return compacted_load_cluster_from_disk(m, lcn, lookahead);
>
> return -EINVAL;
> }
> @@ -399,7 +428,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
>
> /* load extent head logical cluster if needed */
> lcn -= lookback_distance;
> - err = z_erofs_load_cluster_from_disk(m, lcn);
> + err = z_erofs_load_cluster_from_disk(m, lcn, false);
> if (err)
> return err;
>
> @@ -450,7 +479,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
> if (m->compressedlcs)
> goto out;
>
> - err = z_erofs_load_cluster_from_disk(m, lcn);
> + err = z_erofs_load_cluster_from_disk(m, lcn, false);
> if (err)
> return err;
>
> @@ -498,6 +527,48 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
> return -EFSCORRUPTED;
> }
>
> +static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
> +{
> + struct inode *inode = m->inode;
> + struct erofs_inode *vi = EROFS_I(inode);
> + struct erofs_map_blocks *map = m->map;
> + unsigned int lclusterbits = vi->z_logical_clusterbits;
> + u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits;
> + int err;
> +
> + do {
> + /* handle the last EOF pcluster (no next HEAD lcluster) */
> + if ((lcn << lclusterbits) >= inode->i_size) {
> + map->m_llen = inode->i_size - map->m_la;
> + return 0;
> + }
> +
> + err = z_erofs_load_cluster_from_disk(m, lcn, true);
> + if (err)
> + return err;
> +
> + if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
> + if (!m->delta[1])
> + DBG_BUGON(m->clusterofs != 1 << lclusterbits);
DBG_BUGON(!m->delta[1] &&
m->clusterofs != 1 << lclusterbits);
> + } else if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN ||
> + m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD) {
> + /* go on until the next HEAD lcluster */
> + if (lcn != headlcn)
> + break;
> + m->delta[1] = 1;
If I didn't miss anything, return value [1] of get_compacted_la_distance()
won't be used anyway here? right?
Thanks,
> + } else {
> + erofs_err(inode->i_sb, "unknown type %u @ lcn %llu of nid %llu",
> + m->type, lcn, vi->nid);
> + DBG_BUGON(1);
> + return -EOPNOTSUPP;
> + }
> + lcn += m->delta[1];
> + } while (m->delta[1]);
> +
> + map->m_llen = (lcn << lclusterbits) + m->clusterofs - map->m_la;
> + return 0;
> +}
> +
> int z_erofs_map_blocks_iter(struct inode *inode,
> struct erofs_map_blocks *map,
> int flags)
> @@ -531,7 +602,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
> initial_lcn = ofs >> lclusterbits;
> endoff = ofs & ((1 << lclusterbits) - 1);
>
> - err = z_erofs_load_cluster_from_disk(&m, initial_lcn);
> + err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false);
> if (err)
> goto unmap_out;
>
> @@ -581,6 +652,12 @@ int z_erofs_map_blocks_iter(struct inode *inode,
> err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
> if (err)
> goto out;
> +
> + if (flags & EROFS_GET_BLOCKS_FIEMAP) {
> + err = z_erofs_get_extent_decompressedlen(&m);
> + if (!err)
> + map->m_flags |= EROFS_MAP_FULL_MAPPED;
> + }
> unmap_out:
> if (m.kaddr)
> kunmap_atomic(m.kaddr);
>
Powered by blists - more mailing lists