When --incremental=data is run on a merged image, erofs_write_device_table() leaves unified addresses and total block count stale after the primary device grows. Fix it by rewriting the slots in place with updated uniaddr value.
Reproducer: mkfs.erofs -Enoinline_data a.erofs a/ mkfs.erofs -Enoinline_data b.erofs b/ mkfs.erofs merged.erofs a.erofs b.erofs mkfs.erofs --incremental=data merged.erofs c/ Signed-off-by: Jonathan Calmels <[email protected]> --- include/erofs/internal.h | 6 ++---- lib/super.c | 27 +++++++++++++++------------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/include/erofs/internal.h b/include/erofs/internal.h index 95f5627..b10e447 100644 --- a/include/erofs/internal.h +++ b/include/erofs/internal.h @@ -123,10 +123,8 @@ struct erofs_sb_info { u32 checksum; u16 available_compr_algs; u16 extra_devices; - union { - u16 devt_slotoff; /* used for mkfs */ - u16 device_id_mask; /* used for others */ - }; + u16 devt_slotoff; /* used for mkfs */ + u16 device_id_mask; /* used for others */ erofs_nid_t packed_nid; erofs_nid_t metabox_nid; diff --git a/lib/super.c b/lib/super.c index 9e52dd8..672464c 100644 --- a/lib/super.c +++ b/lib/super.c @@ -52,6 +52,7 @@ static int erofs_init_devices(struct erofs_sb_info *sbi, sbi->extra_devices = ondisk_extradevs; sbi->device_id_mask = roundup_pow_of_two(ondisk_extradevs + 1) - 1; + sbi->devt_slotoff = le16_to_cpu(dsb->devt_slotoff); sbi->devs = calloc(ondisk_extradevs, sizeof(*sbi->devs)); if (!sbi->devs) return -ENOMEM; @@ -424,15 +425,15 @@ int erofs_write_device_table(struct erofs_sb_info *sbi) if (!sbi->extra_devices) goto out; if (!bh) { - if (erofs_sb_has_device_table(sbi)) - return 0; - return -EINVAL; - } - - pos = erofs_btell(bh, false); - if (pos == EROFS_NULL_ADDR) { - DBG_BUGON(1); - return -EINVAL; + if (!erofs_sb_has_device_table(sbi)) + return -EINVAL; + pos = sbi->devt_slotoff * EROFS_DEVT_SLOT_SIZE; + } else { + pos = erofs_btell(bh, false); + if (pos == EROFS_NULL_ADDR) { + DBG_BUGON(1); + return -EINVAL; + } } i = 0; @@ -452,9 +453,11 @@ int erofs_write_device_table(struct erofs_sb_info *sbi) nblocks += sbi->devs[i].blocks; } while (++i < sbi->extra_devices); - bh->op = &erofs_drop_directly_bhops; - erofs_bdrop(bh, false); - sbi->bh_devt = NULL; + if (bh) { + bh->op = &erofs_drop_directly_bhops; + erofs_bdrop(bh, false); + sbi->bh_devt = NULL; + } out: sbi->total_blocks = nblocks; return 0; -- 2.53.0
