diff options
Diffstat (limited to 'fs/erofs/data.c')
-rw-r--r-- | fs/erofs/data.c | 165 |
1 files changed, 105 insertions, 60 deletions
diff --git a/fs/erofs/data.c b/fs/erofs/data.c index 761896054c8..f4b21d7917a 100644 --- a/fs/erofs/data.c +++ b/fs/erofs/data.c @@ -12,23 +12,23 @@ static int erofs_map_blocks_flatmode(struct erofs_inode *inode, struct erofs_inode *vi = inode; bool tailendpacking = (vi->datalayout == EROFS_INODE_FLAT_INLINE); - nblocks = DIV_ROUND_UP(inode->i_size, EROFS_BLKSIZ); + nblocks = BLK_ROUND_UP(inode->i_size); lastblk = nblocks - tailendpacking; /* there is no hole in flatmode */ map->m_flags = EROFS_MAP_MAPPED; - if (offset < blknr_to_addr(lastblk)) { - map->m_pa = blknr_to_addr(vi->u.i_blkaddr) + map->m_la; - map->m_plen = blknr_to_addr(lastblk) - offset; + if (offset < erofs_pos(lastblk)) { + map->m_pa = erofs_pos(vi->u.i_blkaddr) + map->m_la; + map->m_plen = erofs_pos(lastblk) - offset; } else if (tailendpacking) { /* 2 - inode inline B: inode, [xattrs], inline last blk... */ map->m_pa = iloc(vi->nid) + vi->inode_isize + vi->xattr_isize + erofs_blkoff(map->m_la); map->m_plen = inode->i_size - offset; - /* inline data should be located in one meta block */ - if (erofs_blkoff(map->m_pa) + map->m_plen > PAGE_SIZE) { + /* inline data should be located in the same meta block */ + if (erofs_blkoff(map->m_pa) + map->m_plen > erofs_blksiz()) { erofs_err("inline data cross block boundary @ nid %" PRIu64, vi->nid); DBG_BUGON(1); @@ -55,7 +55,7 @@ int erofs_map_blocks(struct erofs_inode *inode, { struct erofs_inode *vi = inode; struct erofs_inode_chunk_index *idx; - u8 buf[EROFS_BLKSIZ]; + u8 buf[EROFS_MAX_BLOCK_SIZE]; u64 chunknr; unsigned int unit; erofs_off_t pos; @@ -87,7 +87,7 @@ int erofs_map_blocks(struct erofs_inode *inode, map->m_la = chunknr << vi->u.chunkbits; map->m_plen = min_t(erofs_off_t, 1UL << vi->u.chunkbits, - roundup(inode->i_size - map->m_la, EROFS_BLKSIZ)); + roundup(inode->i_size - map->m_la, erofs_blksiz())); /* handle block map */ if (!(vi->u.chunkformat & EROFS_CHUNK_FORMAT_INDEXES)) { @@ -96,7 +96,7 @@ int erofs_map_blocks(struct erofs_inode *inode, if (le32_to_cpu(*blkaddr) == EROFS_NULL_ADDR) { map->m_flags = 0; } else { - map->m_pa = blknr_to_addr(le32_to_cpu(*blkaddr)); + map->m_pa = erofs_pos(le32_to_cpu(*blkaddr)); map->m_flags = EROFS_MAP_MAPPED; } goto out; @@ -110,7 +110,7 @@ int erofs_map_blocks(struct erofs_inode *inode, default: map->m_deviceid = le16_to_cpu(idx->device_id) & sbi.device_id_mask; - map->m_pa = blknr_to_addr(le32_to_cpu(idx->blkaddr)); + map->m_pa = erofs_pos(le32_to_cpu(idx->blkaddr)); map->m_flags = EROFS_MAP_MAPPED; break; } @@ -119,23 +119,23 @@ out: return err; } -int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map) +int erofs_map_dev(struct erofs_map_dev *map) { struct erofs_device_info *dif; int id; if (map->m_deviceid) { - if (sbi->extra_devices < map->m_deviceid) + if (sbi.extra_devices < map->m_deviceid) return -ENODEV; - } else if (sbi->extra_devices) { - for (id = 0; id < sbi->extra_devices; ++id) { + } else if (sbi.extra_devices) { + for (id = 0; id < sbi.extra_devices; ++id) { erofs_off_t startoff, length; - dif = sbi->devs + id; + dif = sbi.devs + id; if (!dif->mapped_blkaddr) continue; - startoff = blknr_to_addr(dif->mapped_blkaddr); - length = blknr_to_addr(dif->blocks); + startoff = erofs_pos(dif->mapped_blkaddr); + length = erofs_pos(dif->blocks); if (map->m_pa >= startoff && map->m_pa < startoff + length) { @@ -147,19 +147,38 @@ int erofs_map_dev(struct erofs_sb_info *sbi, struct erofs_map_dev *map) return 0; } +int erofs_read_one_data(struct erofs_map_blocks *map, char *buffer, u64 offset, + size_t len) +{ + struct erofs_map_dev mdev; + int ret; + + mdev = (struct erofs_map_dev) { + .m_deviceid = map->m_deviceid, + .m_pa = map->m_pa, + }; + ret = erofs_map_dev(&mdev); + if (ret) + return ret; + + ret = erofs_dev_read(mdev.m_deviceid, buffer, mdev.m_pa + offset, len); + if (ret < 0) + return -EIO; + return 0; +} + static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, erofs_off_t size, erofs_off_t offset) { struct erofs_map_blocks map = { .index = UINT_MAX, }; - struct erofs_map_dev mdev; int ret; erofs_off_t ptr = offset; while (ptr < offset + size) { char *const estart = buffer + ptr - offset; - erofs_off_t eend; + erofs_off_t eend, moff = 0; map.m_la = ptr; ret = erofs_map_blocks(inode, &map, 0); @@ -168,14 +187,6 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, DBG_BUGON(map.m_plen != map.m_llen); - mdev = (struct erofs_map_dev) { - .m_deviceid = map.m_deviceid, - .m_pa = map.m_pa, - }; - ret = erofs_map_dev(&sbi, &mdev); - if (ret) - return ret; - /* trim extent */ eend = min(offset + size, map.m_la + map.m_llen); DBG_BUGON(ptr < map.m_la); @@ -193,19 +204,73 @@ static int erofs_read_raw_data(struct erofs_inode *inode, char *buffer, } if (ptr > map.m_la) { - mdev.m_pa += ptr - map.m_la; + moff = ptr - map.m_la; map.m_la = ptr; } - ret = erofs_dev_read(mdev.m_deviceid, estart, mdev.m_pa, - eend - map.m_la); - if (ret < 0) - return -EIO; + ret = erofs_read_one_data(&map, estart, moff, eend - map.m_la); + if (ret) + return ret; ptr = eend; } return 0; } +int z_erofs_read_one_data(struct erofs_inode *inode, + struct erofs_map_blocks *map, char *raw, char *buffer, + erofs_off_t skip, erofs_off_t length, bool trimmed) +{ + struct erofs_map_dev mdev; + int ret = 0; + + if (map->m_flags & EROFS_MAP_FRAGMENT) { + struct erofs_inode packed_inode = { + .nid = sbi.packed_nid, + }; + + ret = erofs_read_inode_from_disk(&packed_inode); + if (ret) { + erofs_err("failed to read packed inode from disk"); + return ret; + } + + return erofs_pread(&packed_inode, buffer, length - skip, + inode->fragmentoff + skip); + } + + /* no device id here, thus it will always succeed */ + mdev = (struct erofs_map_dev) { + .m_pa = map->m_pa, + }; + ret = erofs_map_dev(&mdev); + if (ret) { + DBG_BUGON(1); + return ret; + } + + ret = erofs_dev_read(mdev.m_deviceid, raw, mdev.m_pa, map->m_plen); + if (ret < 0) + return ret; + + ret = z_erofs_decompress(&(struct z_erofs_decompress_req) { + .in = raw, + .out = buffer, + .decodedskip = skip, + .interlaced_offset = + map->m_algorithmformat == Z_EROFS_COMPRESSION_INTERLACED ? + erofs_blkoff(map->m_la) : 0, + .inputsize = map->m_plen, + .decodedlength = length, + .alg = map->m_algorithmformat, + .partial_decoding = trimmed ? true : + !(map->m_flags & EROFS_MAP_FULL_MAPPED) || + (map->m_flags & EROFS_MAP_PARTIAL_REF), + }); + if (ret < 0) + return ret; + return 0; +} + static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, erofs_off_t size, erofs_off_t offset) { @@ -213,8 +278,7 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, struct erofs_map_blocks map = { .index = UINT_MAX, }; - struct erofs_map_dev mdev; - bool partial; + bool trimmed; unsigned int bufsize = 0; char *raw = NULL; int ret = 0; @@ -227,27 +291,17 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, if (ret) break; - /* no device id here, thus it will always succeed */ - mdev = (struct erofs_map_dev) { - .m_pa = map.m_pa, - }; - ret = erofs_map_dev(&sbi, &mdev); - if (ret) { - DBG_BUGON(1); - break; - } - /* * trim to the needed size if the returned extent is quite * larger than requested, and set up partial flag as well. */ if (end < map.m_la + map.m_llen) { length = end - map.m_la; - partial = true; + trimmed = true; } else { DBG_BUGON(end != map.m_la + map.m_llen); length = map.m_llen; - partial = !(map.m_flags & EROFS_MAP_FULL_MAPPED); + trimmed = false; } if (map.m_la < offset) { @@ -272,19 +326,10 @@ static int z_erofs_read_data(struct erofs_inode *inode, char *buffer, break; } } - ret = erofs_dev_read(mdev.m_deviceid, raw, mdev.m_pa, map.m_plen); - if (ret < 0) - break; - ret = z_erofs_decompress(&(struct z_erofs_decompress_req) { - .in = raw, - .out = buffer + end - offset, - .decodedskip = skip, - .inputsize = map.m_plen, - .decodedlength = length, - .alg = map.m_algorithmformat, - .partial_decoding = partial - }); + ret = z_erofs_read_one_data(inode, &map, raw, + buffer + end - offset, skip, length, + trimmed); if (ret < 0) break; } @@ -301,8 +346,8 @@ int erofs_pread(struct erofs_inode *inode, char *buf, case EROFS_INODE_FLAT_INLINE: case EROFS_INODE_CHUNK_BASED: return erofs_read_raw_data(inode, buf, count, offset); - case EROFS_INODE_FLAT_COMPRESSION_LEGACY: - case EROFS_INODE_FLAT_COMPRESSION: + case EROFS_INODE_COMPRESSED_FULL: + case EROFS_INODE_COMPRESSED_COMPACT: return z_erofs_read_data(inode, buf, count, offset); default: break; |