Messages in this thread Patch in this message | | | From | Yue Hu <> | Subject | [RFC PATCH] erofs: support tail-packing inline compressed data | Date | Wed, 17 Nov 2021 17:25:54 +0800 |
| |
Currently, we have already support tail-packing inline for uncompressed file, let's also support it for compressed file to decrease tail extent I/O and save more space.
Signed-off-by: Yue Hu <huyue2@yulong.com> --- fs/erofs/compress.h | 2 +- fs/erofs/decompressor.c | 29 ++++--- fs/erofs/erofs_fs.h | 10 ++- fs/erofs/internal.h | 3 + fs/erofs/super.c | 3 + fs/erofs/zdata.c | 76 +++++++++++++++---- fs/erofs/zdata.h | 7 +- fs/erofs/zmap.c | 164 ++++++++++++++++++++++++++++++++++------ 8 files changed, 238 insertions(+), 56 deletions(-)
diff --git a/fs/erofs/compress.h b/fs/erofs/compress.h index 579406504919..9de40229be14 100644 --- a/fs/erofs/compress.h +++ b/fs/erofs/compress.h @@ -12,7 +12,7 @@ struct z_erofs_decompress_req { struct super_block *sb; struct page **in, **out; - unsigned short pageofs_out; + unsigned short pageofs_in, pageofs_out; unsigned int inputsize, outputsize; /* indicate the algorithm will be used for decompression */ diff --git a/fs/erofs/decompressor.c b/fs/erofs/decompressor.c index bf37fc76b182..9ce4b2d23e29 100644 --- a/fs/erofs/decompressor.c +++ b/fs/erofs/decompressor.c @@ -186,7 +186,7 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, u8 *out) { unsigned int inputmargin; - u8 *headpage, *src; + u8 *headpage, *src, *in; bool support_0padding; int ret, maptype; @@ -196,7 +196,7 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, support_0padding = false; /* decompression inplace is only safe when 0padding is enabled */ - if (erofs_sb_has_lz4_0padding(EROFS_SB(rq->sb))) { + if (!rq->pageofs_in && erofs_sb_has_lz4_0padding(EROFS_SB(rq->sb))) { support_0padding = true; while (!headpage[inputmargin & ~PAGE_MASK]) @@ -215,20 +215,22 @@ static int z_erofs_lz4_decompress_mem(struct z_erofs_decompress_req *rq, if (IS_ERR(src)) return PTR_ERR(src); + in = src + rq->pageofs_in + inputmargin; + /* legacy format could compress extra data in a pcluster. */ if (rq->partial_decoding || !support_0padding) - ret = LZ4_decompress_safe_partial(src + inputmargin, out, - rq->inputsize, rq->outputsize, rq->outputsize); + ret = LZ4_decompress_safe_partial(in, out, rq->inputsize, + rq->outputsize, rq->outputsize); else - ret = LZ4_decompress_safe(src + inputmargin, out, - rq->inputsize, rq->outputsize); + ret = LZ4_decompress_safe(in, out, rq->inputsize, + rq->outputsize); if (ret != rq->outputsize) { erofs_err(rq->sb, "failed to decompress %d in[%u, %u] out[%u]", ret, rq->inputsize, inputmargin, rq->outputsize); print_hex_dump(KERN_DEBUG, "[ in]: ", DUMP_PREFIX_OFFSET, - 16, 1, src + inputmargin, rq->inputsize, true); + 16, 1, in, rq->inputsize, true); print_hex_dump(KERN_DEBUG, "[out]: ", DUMP_PREFIX_OFFSET, 16, 1, out, rq->outputsize, true); @@ -299,7 +301,7 @@ static int z_erofs_shifted_transform(struct z_erofs_decompress_req *rq, { const unsigned int nrpages_out = PAGE_ALIGN(rq->pageofs_out + rq->outputsize) >> PAGE_SHIFT; - const unsigned int righthalf = PAGE_SIZE - rq->pageofs_out; + unsigned int righthalf = PAGE_SIZE - rq->pageofs_out; unsigned char *src, *dst; if (nrpages_out > 2) { @@ -312,20 +314,25 @@ static int z_erofs_shifted_transform(struct z_erofs_decompress_req *rq, return 0; } + if (nrpages_out == 1 && rq->outputsize < righthalf) + righthalf = rq->outputsize; + src = kmap_atomic(*rq->in); if (rq->out[0]) { dst = kmap_atomic(rq->out[0]); - memcpy(dst + rq->pageofs_out, src, righthalf); + memcpy(dst + rq->pageofs_out, src + rq->pageofs_in, righthalf); kunmap_atomic(dst); } if (nrpages_out == 2) { DBG_BUGON(!rq->out[1]); if (rq->out[1] == *rq->in) { - memmove(src, src + righthalf, rq->pageofs_out); + memmove(src, src + rq->pageofs_in + righthalf, + rq->pageofs_out); } else { dst = kmap_atomic(rq->out[1]); - memcpy(dst, src + righthalf, rq->pageofs_out); + memcpy(dst, src + rq->pageofs_in + righthalf, + rq->pageofs_out); kunmap_atomic(dst); } } diff --git a/fs/erofs/erofs_fs.h b/fs/erofs/erofs_fs.h index 083997a034e5..19153cd6f5e8 100644 --- a/fs/erofs/erofs_fs.h +++ b/fs/erofs/erofs_fs.h @@ -23,13 +23,15 @@ #define EROFS_FEATURE_INCOMPAT_CHUNKED_FILE 0x00000004 #define EROFS_FEATURE_INCOMPAT_DEVICE_TABLE 0x00000008 #define EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 0x00000008 +#define EROFS_FEATURE_INCOMPAT_TAIL_PACKING 0x00000010 #define EROFS_ALL_FEATURE_INCOMPAT \ (EROFS_FEATURE_INCOMPAT_LZ4_0PADDING | \ EROFS_FEATURE_INCOMPAT_COMPR_CFGS | \ EROFS_FEATURE_INCOMPAT_BIG_PCLUSTER | \ EROFS_FEATURE_INCOMPAT_CHUNKED_FILE | \ EROFS_FEATURE_INCOMPAT_DEVICE_TABLE | \ - EROFS_FEATURE_INCOMPAT_COMPR_HEAD2) + EROFS_FEATURE_INCOMPAT_COMPR_HEAD2 | \ + EROFS_FEATURE_INCOMPAT_TAIL_PACKING) #define EROFS_SB_EXTSLOT_SIZE 16 @@ -292,13 +294,17 @@ struct z_erofs_lzma_cfgs { * (4B) + 2B + (4B) if compacted 2B is on. * bit 1 : HEAD1 big pcluster (0 - off; 1 - on) * bit 2 : HEAD2 big pcluster (0 - off; 1 - on) + * bit 3 : tail-packing inline data */ #define Z_EROFS_ADVISE_COMPACTED_2B 0x0001 #define Z_EROFS_ADVISE_BIG_PCLUSTER_1 0x0002 #define Z_EROFS_ADVISE_BIG_PCLUSTER_2 0x0004 +#define Z_EROFS_ADVISE_INLINE_DATA 0x0008 struct z_erofs_map_header { - __le32 h_reserved1; + __le16 h_reserved1; + /* record the size of tail-packing pcluster */ + __le16 h_idata_size; __le16 h_advise; /* * bit 0-3 : algorithm type of head 1 (logical cluster type 01); diff --git a/fs/erofs/internal.h b/fs/erofs/internal.h index 3265688af7f9..9ab3d38c7919 100644 --- a/fs/erofs/internal.h +++ b/fs/erofs/internal.h @@ -262,6 +262,7 @@ EROFS_FEATURE_FUNCS(lz4_0padding, incompat, INCOMPAT_LZ4_0PADDING) EROFS_FEATURE_FUNCS(compr_cfgs, incompat, INCOMPAT_COMPR_CFGS) EROFS_FEATURE_FUNCS(big_pcluster, incompat, INCOMPAT_BIG_PCLUSTER) EROFS_FEATURE_FUNCS(device_table, incompat, INCOMPAT_DEVICE_TABLE) +EROFS_FEATURE_FUNCS(tail_packing, incompat, INCOMPAT_TAIL_PACKING) EROFS_FEATURE_FUNCS(sb_chksum, compat, COMPAT_SB_CHKSUM) /* atomic flag definitions */ @@ -296,6 +297,8 @@ struct erofs_inode { unsigned short z_advise; unsigned char z_algorithmtype[2]; unsigned char z_logical_clusterbits; + unsigned short z_idata_size; + unsigned long z_idata_headlcn; }; #endif /* CONFIG_EROFS_FS_ZIP */ }; diff --git a/fs/erofs/super.c b/fs/erofs/super.c index 6a969b1e0ee6..6f8bb83795a1 100644 --- a/fs/erofs/super.c +++ b/fs/erofs/super.c @@ -411,6 +411,9 @@ static int erofs_read_superblock(struct super_block *sb) /* handle multiple devices */ ret = erofs_init_devices(sb, dsb); + + if (erofs_sb_has_tail_packing(sbi)) + erofs_info(sb, "EXPERIMENTAL compression inline data feature in use. Use at your own risk!"); out: kunmap(page); put_page(page); diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c index bcb1b91b234f..85c46170598d 100644 --- a/fs/erofs/zdata.c +++ b/fs/erofs/zdata.c @@ -432,7 +432,7 @@ static int z_erofs_lookup_collection(struct z_erofs_collector *clt, } cl = z_erofs_primarycollection(pcl); - if (cl->pageofs != (map->m_la & ~PAGE_MASK)) { + if (cl->pageofs_out != (map->m_la & ~PAGE_MASK)) { DBG_BUGON(1); return -EFSCORRUPTED; } @@ -472,6 +472,7 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, struct z_erofs_pcluster *pcl; struct z_erofs_collection *cl; struct erofs_workgroup *grp; + unsigned int nrpages; int err; if (!(map->m_flags & EROFS_MAP_ENCODED)) { @@ -479,13 +480,23 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, return -EFSCORRUPTED; } + if (map->m_plen < EROFS_BLKSIZ && !(map->m_flags & EROFS_MAP_META)) + nrpages = 1; + else + nrpages = map->m_plen >> PAGE_SHIFT; + /* no available pcluster, let's allocate one */ - pcl = z_erofs_alloc_pcluster(map->m_plen >> PAGE_SHIFT); + pcl = z_erofs_alloc_pcluster(nrpages); if (IS_ERR(pcl)) return PTR_ERR(pcl); - atomic_set(&pcl->obj.refcount, 1); - pcl->obj.index = map->m_pa >> PAGE_SHIFT; + pcl->pclusterlen = map->m_plen < EROFS_BLKSIZ ? map->m_plen : 0; + + if (!(map->m_flags & EROFS_MAP_META)) { + atomic_set(&pcl->obj.refcount, 1); + pcl->obj.index = map->m_pa >> PAGE_SHIFT; + } + pcl->algorithmformat = map->m_algorithmformat; pcl->length = (map->m_llen << Z_EROFS_PCLUSTER_LENGTH_BIT) | (map->m_flags & EROFS_MAP_FULL_MAPPED ? @@ -496,7 +507,16 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, clt->mode = COLLECT_PRIMARY_FOLLOWED; cl = z_erofs_primarycollection(pcl); - cl->pageofs = map->m_la & ~PAGE_MASK; + cl->pageofs_out = map->m_la & ~PAGE_MASK; + cl->pageofs_in = 0; + + /* no inplace I/O if inline and fill compressed page first */ + if (map->m_flags & EROFS_MAP_META) { + cl->pageofs_in = map->m_pa & ~PAGE_MASK; + + clt->mode = COLLECT_PRIMARY_FOLLOWED_NOINPLACE; + WRITE_ONCE(pcl->compressed_pages[0], map->mpage); + } /* * lock all primary followed works before visible to others @@ -505,6 +525,9 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, mutex_init(&cl->lock); DBG_BUGON(!mutex_trylock(&cl->lock)); + if (map->m_flags & EROFS_MAP_META) + goto skip_workgroup; + grp = erofs_insert_workgroup(inode->i_sb, &pcl->obj); if (IS_ERR(grp)) { err = PTR_ERR(grp); @@ -516,6 +539,8 @@ static int z_erofs_register_collection(struct z_erofs_collector *clt, err = -EEXIST; goto err_out; } + +skip_workgroup: /* used to check tail merging loop due to corrupted images */ if (clt->owned_head == Z_EROFS_PCLUSTER_TAIL) clt->tailpcl = pcl; @@ -543,6 +568,9 @@ static int z_erofs_collector_begin(struct z_erofs_collector *clt, DBG_BUGON(clt->owned_head == Z_EROFS_PCLUSTER_NIL); DBG_BUGON(clt->owned_head == Z_EROFS_PCLUSTER_TAIL_CLOSED); + if (map->m_flags & EROFS_MAP_META) + goto collection; + if (!PAGE_ALIGNED(map->m_pa)) { DBG_BUGON(1); return -EINVAL; @@ -552,6 +580,7 @@ static int z_erofs_collector_begin(struct z_erofs_collector *clt, if (grp) { clt->pcl = container_of(grp, struct z_erofs_pcluster, obj); } else { +collection: ret = z_erofs_register_collection(clt, inode, map); if (!ret) @@ -692,6 +721,9 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, if (err) goto err_out; + if (map->m_flags & EROFS_MAP_META) + goto hitted; + /* preload all compressed pages (maybe downgrade role if necessary) */ if (should_alloc_managed_pages(fe, sbi->opt.cache_strategy, map->m_la)) cache_strategy = TRYALLOC; @@ -832,6 +864,13 @@ static void z_erofs_decompressqueue_endio(struct bio *bio) bio_put(bio); } +static inline bool z_erofs_pcluster_is_inline(struct z_erofs_pcluster *pcl) +{ + struct z_erofs_collection *cl = z_erofs_primarycollection(pcl); + + return !!cl->pageofs_in; +} + static int z_erofs_decompress_pcluster(struct super_block *sb, struct z_erofs_pcluster *pcl, struct page **pagepool) @@ -963,20 +1002,22 @@ static int z_erofs_decompress_pcluster(struct super_block *sb, goto out; llen = pcl->length >> Z_EROFS_PCLUSTER_LENGTH_BIT; - if (nr_pages << PAGE_SHIFT >= cl->pageofs + llen) { + if (nr_pages << PAGE_SHIFT >= cl->pageofs_out + llen) { outputsize = llen; partial = !(pcl->length & Z_EROFS_PCLUSTER_FULL_LENGTH); } else { - outputsize = (nr_pages << PAGE_SHIFT) - cl->pageofs; + outputsize = (nr_pages << PAGE_SHIFT) - cl->pageofs_out; partial = true; } - inputsize = pcl->pclusterpages * PAGE_SIZE; + inputsize = pcl->pclusterlen ? pcl->pclusterlen : + pcl->pclusterpages * PAGE_SIZE; err = z_erofs_decompress(&(struct z_erofs_decompress_req) { .sb = sb, .in = compressed_pages, .out = pages, - .pageofs_out = cl->pageofs, + .pageofs_in = cl->pageofs_in, + .pageofs_out = cl->pageofs_out, .inputsize = inputsize, .outputsize = outputsize, .alg = pcl->algorithmformat, @@ -1290,6 +1331,13 @@ static void z_erofs_submit_queue(struct super_block *sb, pcl = container_of(owned_head, struct z_erofs_pcluster, next); + /* close the main owned chain at first */ + owned_head = cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL, + Z_EROFS_PCLUSTER_TAIL_CLOSED); + + if (z_erofs_pcluster_is_inline(pcl)) + goto noio_submission; + /* no device id here, thus it will always succeed */ mdev = (struct erofs_map_dev) { .m_pa = blknr_to_addr(pcl->obj.index), @@ -1299,10 +1347,6 @@ static void z_erofs_submit_queue(struct super_block *sb, cur = erofs_blknr(mdev.m_pa); end = cur + pcl->pclusterpages; - /* close the main owned chain at first */ - owned_head = cmpxchg(&pcl->next, Z_EROFS_PCLUSTER_TAIL, - Z_EROFS_PCLUSTER_TAIL_CLOSED); - do { struct page *page; @@ -1341,10 +1385,12 @@ static void z_erofs_submit_queue(struct super_block *sb, bypass = false; } while (++cur < end); - if (!bypass) + if (!bypass) { qtail[JQ_SUBMIT] = &pcl->next; - else + } else { +noio_submission: move_to_bypass_jobqueue(pcl, qtail, owned_head); + } } while (owned_head != Z_EROFS_PCLUSTER_TAIL); if (bio) diff --git a/fs/erofs/zdata.h b/fs/erofs/zdata.h index 879df5362777..cc724c51eda8 100644 --- a/fs/erofs/zdata.h +++ b/fs/erofs/zdata.h @@ -25,8 +25,8 @@ struct z_erofs_collection { struct mutex lock; - /* I: page offset of start position of decompression */ - unsigned short pageofs; + /* I: page offset of start position of (de)compression */ + unsigned short pageofs_in, pageofs_out; /* L: maximum relative page index in pagevec[] */ unsigned short nr_pages; @@ -62,6 +62,9 @@ struct z_erofs_pcluster { /* A: lower limit of decompressed length and if full length or not */ unsigned int length; + /* I: tail-packing physical cluster length */ + unsigned short pclusterlen; + /* I: physical cluster size in pages */ unsigned short pclusterpages; diff --git a/fs/erofs/zmap.c b/fs/erofs/zmap.c index 660489a7fb64..e62b81c94865 100644 --- a/fs/erofs/zmap.c +++ b/fs/erofs/zmap.c @@ -7,6 +7,10 @@ #include <asm/unaligned.h> #include <trace/events/erofs.h> +static int z_erofs_do_map_blocks(struct inode *inode, + struct erofs_map_blocks *map, + int flags); + int z_erofs_fill_inode(struct inode *inode) { struct erofs_inode *const vi = EROFS_I(inode); @@ -18,12 +22,74 @@ int z_erofs_fill_inode(struct inode *inode) vi->z_algorithmtype[0] = 0; vi->z_algorithmtype[1] = 0; vi->z_logical_clusterbits = LOG_BLOCK_SIZE; + vi->z_idata_size = 0; set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); + + DBG_BUGON(erofs_sb_has_tail_packing(sbi)); } inode->i_mapping->a_ops = &z_erofs_aops; return 0; } +static erofs_off_t compacted_inline_data_addr(struct erofs_inode *vi, + erofs_off_t i_off, + unsigned int totalidx) +{ + const erofs_off_t ebase = ALIGN(i_off + vi->inode_isize + + vi->xattr_isize, 8) + + sizeof(struct z_erofs_map_header); + unsigned int compacted_4b_initial, compacted_4b_end; + unsigned int compacted_2b; + erofs_off_t addr; + + compacted_4b_initial = (32 - ebase % 32) / 4; + if (compacted_4b_initial == 32 / 4) + compacted_4b_initial = 0; + + if (compacted_4b_initial > totalidx) { + compacted_4b_initial = 0; + compacted_2b = 0; + } else if (vi->z_advise & Z_EROFS_ADVISE_COMPACTED_2B) { + compacted_2b = rounddown(totalidx - compacted_4b_initial, 16); + } else + compacted_2b = 0; + + compacted_4b_end = totalidx - compacted_4b_initial - compacted_2b; + + addr = ebase + compacted_4b_initial * 4 + compacted_2b * 2; + if (compacted_4b_end > 1) + addr += (compacted_4b_end / 2) * 8; + if (compacted_4b_end % 2) + addr += 8; + + return addr; +} + +static erofs_off_t legacy_inline_data_addr(struct erofs_inode *vi, + erofs_off_t i_off, + unsigned int totalidx) +{ + return Z_EROFS_VLE_LEGACY_INDEX_ALIGN(i_off + vi->inode_isize + + vi->xattr_isize) + + totalidx * sizeof(struct z_erofs_vle_decompressed_index); +} + +static erofs_off_t z_erofs_inline_data_addr(struct inode *inode) +{ + struct erofs_inode *const vi = EROFS_I(inode); + const unsigned int datamode = vi->datalayout; + const unsigned int totalidx = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); + const erofs_off_t ibase = iloc(EROFS_I_SB(inode), vi->nid); + + if (datamode == EROFS_INODE_FLAT_COMPRESSION) + return compacted_inline_data_addr(vi, ibase, totalidx); + + if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY) + return legacy_inline_data_addr(vi, ibase, totalidx); + + return -EINVAL; +} + static int z_erofs_fill_inode_lazy(struct inode *inode) { struct erofs_inode *const vi = EROFS_I(inode); @@ -65,6 +131,7 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) h = kaddr + erofs_blkoff(pos); vi->z_advise = le16_to_cpu(h->h_advise); + vi->z_idata_size = le16_to_cpu(h->h_idata_size); vi->z_algorithmtype[0] = h->h_algorithmtype & 15; vi->z_algorithmtype[1] = h->h_algorithmtype >> 4; @@ -94,13 +161,29 @@ static int z_erofs_fill_inode_lazy(struct inode *inode) err = -EFSCORRUPTED; goto unmap_done; } - /* paired with smp_mb() at the beginning of the function */ - smp_mb(); - set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); unmap_done: kunmap_atomic(kaddr); unlock_page(page); put_page(page); + if (err) + goto out_unlock; + + /* record HEAD lcn for tail-packing pcluster */ + if (vi->z_idata_size) { + struct erofs_map_blocks map = { .m_la = inode->i_size - 1 }; + + err = z_erofs_do_map_blocks(inode, &map, 0); + if (map.mpage) + put_page(map.mpage); + if (err < 0) + goto out_unlock; + + vi->z_idata_headlcn = map.m_la >> vi->z_logical_clusterbits; + } + + /* paired with smp_mb() at the beginning of the function */ + smp_mb(); + set_bit(EROFS_I_Z_INITED_BIT, &vi->flags); out_unlock: clear_and_wake_up_bit(EROFS_I_BL_Z_BIT, &vi->flags); return err; @@ -305,7 +388,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m, } m->clusterofs = lo; m->delta[0] = 0; - /* figout out blkaddr (pblk) for HEAD lclusters */ + /* figure out blkaddr (pblk) for HEAD lclusters */ if (!big_pcluster) { nblk = 1; while (i > 0) { @@ -466,7 +549,8 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m, } static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, - unsigned int initial_lcn) + unsigned int initial_lcn, + bool idatamap) { struct erofs_inode *const vi = EROFS_I(m->inode); struct erofs_map_blocks *const map = m->map; @@ -479,6 +563,11 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m, m->type != Z_EROFS_VLE_CLUSTER_TYPE_HEAD2); DBG_BUGON(m->type != m->headtype); + if (idatamap) { + map->m_plen = vi->z_idata_size; + return 0; + } + if (m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN || ((m->headtype == Z_EROFS_VLE_CLUSTER_TYPE_HEAD1) && !(vi->z_advise & Z_EROFS_ADVISE_BIG_PCLUSTER_1)) || @@ -583,9 +672,9 @@ static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m) return 0; } -int z_erofs_map_blocks_iter(struct inode *inode, - struct erofs_map_blocks *map, - int flags) +static int z_erofs_do_map_blocks(struct inode *inode, + struct erofs_map_blocks *map, + int flags) { struct erofs_inode *const vi = EROFS_I(inode); struct z_erofs_maprecorder m = { @@ -596,20 +685,7 @@ int z_erofs_map_blocks_iter(struct inode *inode, unsigned int lclusterbits, endoff; unsigned long initial_lcn; unsigned long long ofs, end; - - trace_z_erofs_map_blocks_iter_enter(inode, map, flags); - - /* when trying to read beyond EOF, leave it unmapped */ - if (map->m_la >= inode->i_size) { - map->m_llen = map->m_la + 1 - inode->i_size; - map->m_la = inode->i_size; - map->m_flags = 0; - goto out; - } - - err = z_erofs_fill_inode_lazy(inode); - if (err) - goto out; + bool idatamap; lclusterbits = vi->z_logical_clusterbits; ofs = map->m_la; @@ -658,10 +734,23 @@ int z_erofs_map_blocks_iter(struct inode *inode, goto unmap_out; } + /* check if mapping tail-packing data */ + idatamap = vi->z_idata_size && (ofs == inode->i_size - 1 || + m.lcn == vi->z_idata_headlcn); + + /* need to trim tail-packing data if beyond file size */ map->m_llen = end - map->m_la; - map->m_pa = blknr_to_addr(m.pblk); + if (idatamap && end > inode->i_size) + map->m_llen -= end - inode->i_size; - err = z_erofs_get_extent_compressedlen(&m, initial_lcn); + if (idatamap && (vi->z_advise & Z_EROFS_ADVISE_INLINE_DATA)) { + map->m_pa = z_erofs_inline_data_addr(inode); + map->m_flags |= EROFS_MAP_META; + } else { + map->m_pa = blknr_to_addr(m.pblk); + } + + err = z_erofs_get_extent_compressedlen(&m, initial_lcn, idatamap); if (err) goto out; @@ -689,9 +778,34 @@ int z_erofs_map_blocks_iter(struct inode *inode, __func__, map->m_la, map->m_pa, map->m_llen, map->m_plen, map->m_flags); + return err; +} + +int z_erofs_map_blocks_iter(struct inode *inode, + struct erofs_map_blocks *map, + int flags) +{ + int err = 0; + + trace_z_erofs_map_blocks_iter_enter(inode, map, flags); + + /* when trying to read beyond EOF, leave it unmapped */ + if (map->m_la >= inode->i_size) { + map->m_llen = map->m_la + 1 - inode->i_size; + map->m_la = inode->i_size; + map->m_flags = 0; + goto out; + } + + err = z_erofs_fill_inode_lazy(inode); + if (err) + goto out; + + err = z_erofs_do_map_blocks(inode, map, flags); +out: trace_z_erofs_map_blocks_iter_exit(inode, map, flags, err); - /* aggressively BUG_ON iff CONFIG_EROFS_FS_DEBUG is on */ + /* aggressively BUG_ON if CONFIG_EROFS_FS_DEBUG is on */ DBG_BUGON(err < 0 && err != -ENOMEM); return err; } -- 2.17.1
| |