Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f68c34ca authored by Gao Xiang's avatar Gao Xiang Committed by Gao Xiang
Browse files

erofs: fix 1 lcluster-sized pcluster for big pcluster

If the 1st NONHEAD lcluster of a pcluster isn't CBLKCNT lcluster type
rather than a HEAD or PLAIN type instead, which means its pclustersize
_must_ be 1 lcluster (since its uncompressed size < 2 lclusters),
as illustrated below:

       HEAD     HEAD / PLAIN    lcluster type
   ____________ ____________
  |_:__________|_________:__|   file data (uncompressed)
   .                .
  .____________.
  |____________|                pcluster data (compressed)

Such on-disk case was explained before [1] but missed to be handled
properly in the runtime implementation.

It can be observed if manually generating 1 lcluster-sized pcluster
with 2 lclusters (thus CBLKCNT doesn't exist.) Let's fix it now.

[1] https://lore.kernel.org/r/20210407043927.10623-1-xiang@kernel.org

Link: https://lore.kernel.org/r/20210510064715.29123-1-xiang@kernel.org


Fixes: cec6e93beadf ("erofs: support parsing big pcluster compress indexes")
Reviewed-by: default avatarChao Yu <yuchao0@huawei.com>
Signed-off-by: default avatarGao Xiang <xiang@kernel.org>
parent 50ea9ae0
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -449,14 +449,31 @@ static int z_erofs_get_extent_compressedlen(struct z_erofs_maprecorder *m,
	lcn = m->lcn + 1;
	if (m->compressedlcs)
		goto out;
	if (lcn == initial_lcn)
		goto err_bonus_cblkcnt;

	err = z_erofs_load_cluster_from_disk(m, lcn);
	if (err)
		return err;

	/*
	 * If the 1st NONHEAD lcluster has already been handled initially w/o
	 * valid compressedlcs, which means at least it mustn't be CBLKCNT, or
	 * an internal implemenatation error is detected.
	 *
	 * The following code can also handle it properly anyway, but let's
	 * BUG_ON in the debugging mode only for developers to notice that.
	 */
	DBG_BUGON(lcn == initial_lcn &&
		  m->type == Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD);

	switch (m->type) {
	case Z_EROFS_VLE_CLUSTER_TYPE_PLAIN:
	case Z_EROFS_VLE_CLUSTER_TYPE_HEAD:
		/*
		 * if the 1st NONHEAD lcluster is actually PLAIN or HEAD type
		 * rather than CBLKCNT, it's a 1 lcluster-sized pcluster.
		 */
		m->compressedlcs = 1;
		break;
	case Z_EROFS_VLE_CLUSTER_TYPE_NONHEAD:
		if (m->delta[0] != 1)
			goto err_bonus_cblkcnt;