Skip to content

Commit d95ae5e

Browse files
committed
erofs: add support for the full decompressed length
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. Link: https://lore.kernel.org/r/[email protected] Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Gao Xiang <[email protected]>
1 parent d252ff3 commit d95ae5e

File tree

2 files changed

+92
-8
lines changed

2 files changed

+92
-8
lines changed

fs/erofs/internal.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -356,6 +356,11 @@ struct erofs_map_blocks {
356356

357357
/* Flags used by erofs_map_blocks_flatmode() */
358358
#define EROFS_GET_BLOCKS_RAW 0x0001
359+
/*
360+
* Used to get the exact decompressed length, e.g. fiemap (consider lookback
361+
* approach instead if possible since it's more metadata lightweight.)
362+
*/
363+
#define EROFS_GET_BLOCKS_FIEMAP 0x0002
359364

360365
/* zmap.c */
361366
#ifdef CONFIG_EROFS_FS_ZIP

fs/erofs/zmap.c

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -212,9 +212,34 @@ static unsigned int decode_compactedbits(unsigned int lobits,
212212
return lo;
213213
}
214214

215+
static int get_compacted_la_distance(unsigned int lclusterbits,
216+
unsigned int encodebits,
217+
unsigned int vcnt, u8 *in, int i)
218+
{
219+
const unsigned int lomask = (1 << lclusterbits) - 1;
220+
unsigned int lo, d1 = 0;
221+
u8 type;
222+
223+
DBG_BUGON(i >= vcnt);
224+
225+
do {
226+
lo = decode_compactedbits(lclusterbits, lomask,
227+
in, encodebits * i, &type);
228+
229+
if (type != Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD)
230+
return d1;
231+
++d1;
232+
} while (++i < vcnt);
233+
234+
/* vcnt - 1 (Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) item */
235+
if (!(lo & Z_EROFS_VLE_DI_D0_CBLKCNT))
236+
d1 += lo - 1;
237+
return d1;
238+
}
239+
215240
static int unpack_compacted_index(struct z_erofs_maprecorder *m,
216241
unsigned int amortizedshift,
217-
unsigned int eofs)
242+
unsigned int eofs, bool lookahead)
218243
{
219244
struct erofs_inode *const vi = EROFS_I(m->inode);
220245
const unsigned int lclusterbits = vi->z_logical_clusterbits;
@@ -243,6 +268,11 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
243268
m->type = type;
244269
if (type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
245270
m->clusterofs = 1 << lclusterbits;
271+
272+
/* figure out lookahead_distance: delta[1] if needed */
273+
if (lookahead)
274+
m->delta[1] = get_compacted_la_distance(lclusterbits,
275+
encodebits, vcnt, in, i);
246276
if (lo & Z_EROFS_VLE_DI_D0_CBLKCNT) {
247277
if (!big_pcluster) {
248278
DBG_BUGON(1);
@@ -313,7 +343,7 @@ static int unpack_compacted_index(struct z_erofs_maprecorder *m,
313343
}
314344

315345
static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
316-
unsigned long lcn)
346+
unsigned long lcn, bool lookahead)
317347
{
318348
struct inode *const inode = m->inode;
319349
struct erofs_inode *const vi = EROFS_I(inode);
@@ -364,19 +394,20 @@ static int compacted_load_cluster_from_disk(struct z_erofs_maprecorder *m,
364394
err = z_erofs_reload_indexes(m, erofs_blknr(pos));
365395
if (err)
366396
return err;
367-
return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos));
397+
return unpack_compacted_index(m, amortizedshift, erofs_blkoff(pos),
398+
lookahead);
368399
}
369400

370401
static int z_erofs_load_cluster_from_disk(struct z_erofs_maprecorder *m,
371-
unsigned int lcn)
402+
unsigned int lcn, bool lookahead)
372403
{
373404
const unsigned int datamode = EROFS_I(m->inode)->datalayout;
374405

375406
if (datamode == EROFS_INODE_FLAT_COMPRESSION_LEGACY)
376407
return legacy_load_cluster_from_disk(m, lcn);
377408

378409
if (datamode == EROFS_INODE_FLAT_COMPRESSION)
379-
return compacted_load_cluster_from_disk(m, lcn);
410+
return compacted_load_cluster_from_disk(m, lcn, lookahead);
380411

381412
return -EINVAL;
382413
}
@@ -399,7 +430,7 @@ static int z_erofs_extent_lookback(struct z_erofs_maprecorder *m,
399430

400431
/* load extent head logical cluster if needed */
401432
lcn -= lookback_distance;
402-
err = z_erofs_load_cluster_from_disk(m, lcn);
433+
err = z_erofs_load_cluster_from_disk(m, lcn, false);
403434
if (err)
404435
return err;
405436

@@ -450,7 +481,7 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
450481
if (m->compressedlcs)
451482
goto out;
452483

453-
err = z_erofs_load_cluster_from_disk(m, lcn);
484+
err = z_erofs_load_cluster_from_disk(m, lcn, false);
454485
if (err)
455486
return err;
456487

@@ -498,6 +529,48 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
498529
return -EFSCORRUPTED;
499530
}
500531

532+
static int z_erofs_get_extent_decompressedlen(struct z_erofs_maprecorder *m)
533+
{
534+
struct inode *inode = m->inode;
535+
struct erofs_inode *vi = EROFS_I(inode);
536+
struct erofs_map_blocks *map = m->map;
537+
unsigned int lclusterbits = vi->z_logical_clusterbits;
538+
u64 lcn = m->lcn, headlcn = map->m_la >> lclusterbits;
539+
int err;
540+
541+
do {
542+
/* handle the last EOF pcluster (no next HEAD lcluster) */
543+
if ((lcn << lclusterbits) >= inode->i_size) {
544+
map->m_llen = inode->i_size - map->m_la;
545+
return 0;
546+
}
547+
548+
err = z_erofs_load_cluster_from_disk(m, lcn, true);
549+
if (err)
550+
return err;
551+
552+
if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD) {
553+
DBG_BUGON(!m->delta[1] &&
554+
m->clusterofs != 1 << lclusterbits);
555+
} else if (m->type == Z_EROFS_VLE_CLUSTER_TYPE_PLAIN ||
556+
m->type == Z_EROFS_VLE_CLUSTER_TYPE_HEAD) {
557+
/* go on until the next HEAD lcluster */
558+
if (lcn != headlcn)
559+
break;
560+
m->delta[1] = 1;
561+
} else {
562+
erofs_err(inode->i_sb, "unknown type %u @ lcn %llu of nid %llu",
563+
m->type, lcn, vi->nid);
564+
DBG_BUGON(1);
565+
return -EOPNOTSUPP;
566+
}
567+
lcn += m->delta[1];
568+
} while (m->delta[1]);
569+
570+
map->m_llen = (lcn << lclusterbits) + m->clusterofs - map->m_la;
571+
return 0;
572+
}
573+
501574
int z_erofs_map_blocks_iter(struct inode *inode,
502575
struct erofs_map_blocks *map,
503576
int flags)
@@ -531,7 +604,7 @@ int z_erofs_map_blocks_iter(struct inode *inode,
531604
initial_lcn = ofs >> lclusterbits;
532605
endoff = ofs & ((1 << lclusterbits) - 1);
533606

534-
err = z_erofs_load_cluster_from_disk(&m, initial_lcn);
607+
err = z_erofs_load_cluster_from_disk(&m, initial_lcn, false);
535608
if (err)
536609
goto unmap_out;
537610

@@ -581,6 +654,12 @@ int z_erofs_map_blocks_iter(struct inode *inode,
581654
err = z_erofs_get_extent_compressedlen(&m, initial_lcn);
582655
if (err)
583656
goto out;
657+
658+
if (flags & EROFS_GET_BLOCKS_FIEMAP) {
659+
err = z_erofs_get_extent_decompressedlen(&m);
660+
if (!err)
661+
map->m_flags |= EROFS_MAP_FULL_MAPPED;
662+
}
584663
unmap_out:
585664
if (m.kaddr)
586665
kunmap_atomic(m.kaddr);

0 commit comments

Comments
 (0)