[PATCH v2] erofs-utils: fix battach on full buffer block

Hu Weiwen sehuww at mail.scut.edu.cn
Fri Jan 22 03:26:06 AEDT 2021


When __erofs_battach() is called on an buffer block of which
(bb->buffers.off % EROFS_BLKSIZ == 0), `tail_blkaddr' will not be
updated correctly. This bug can be reproduced by:

mkdir bug-repo
head -c 4032 /dev/urandom > bug-repo/1
head -c 4095 /dev/urandom > bug-repo/2
head -c 12345 /dev/urandom > bug-repo/3  # arbitrary size
mkfs.erofs -Eforce-inode-compact bug-repo.erofs.img bug-repo

Then mount this image and see that file `3' in the image is different
from `bug-repo/3'.

This patch fix this by:

* Don't inline tail-end data in this case, since the tail-end data will
be in a different block from inode.
* Correctly handle `battach' in this case.

Signed-off-by: Hu Weiwen <sehuww at mail.scut.edu.cn>
---
Hi Xiang,

I still think send this as a seperate patch would be better. In previous v6
patch, I have fixed the erofs_mapbh() behaviour so that there should be no
user-visible bug introduced in that patch. And this patch is almost unrelated
to that optimization.

Compared with v1, this version fixes an error when compression is enabled.

Thanks,
Hu Weiwen

 lib/cache.c    | 4 ++--
 lib/compress.c | 2 +-
 lib/inode.c    | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/lib/cache.c b/lib/cache.c
index c9a8c50..a7de72d 100644
--- a/lib/cache.c
+++ b/lib/cache.c
@@ -102,7 +102,7 @@ static int __erofs_battach(struct erofs_buffer_block *bb,
 			   bool dryrun)
 {
 	const erofs_off_t alignedoffset = roundup(bb->buffers.off, alignsize);
-	const int oob = cmpsgn(roundup(bb->buffers.off % EROFS_BLKSIZ,
+	const int oob = cmpsgn(roundup((bb->buffers.off - 1) % EROFS_BLKSIZ + 1,
 				       alignsize) + incr + extrasize,
 			       EROFS_BLKSIZ);
 	bool tailupdate = false;
@@ -134,7 +134,7 @@ static int __erofs_battach(struct erofs_buffer_block *bb,
 			tail_blkaddr = blkaddr + BLK_ROUND_UP(bb->buffers.off);
 		erofs_bupdate_mapped(bb);
 	}
-	return (alignedoffset + incr) % EROFS_BLKSIZ;
+	return (alignedoffset + incr - 1) % EROFS_BLKSIZ + 1;
 }

 int erofs_bh_balloon(struct erofs_buffer_head *bh, erofs_off_t incr)
diff --git a/lib/compress.c b/lib/compress.c
index 2b1f93c..670ac72 100644
--- a/lib/compress.c
+++ b/lib/compress.c
@@ -457,7 +457,7 @@ int erofs_write_compressed_file(struct erofs_inode *inode)

 	close(fd);
 	ret = erofs_bh_balloon(bh, blknr_to_addr(compressed_blocks));
-	DBG_BUGON(ret);
+	DBG_BUGON(ret < 0);

 	erofs_info("compressed %s (%llu bytes) into %u blocks",
 		   inode->i_srcpath, (unsigned long long)inode->i_size,
diff --git a/lib/inode.c b/lib/inode.c
index 4ed6aed..d6a64cc 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -531,7 +531,7 @@ int erofs_prepare_tail_block(struct erofs_inode *inode)
 	}
 	/* expend a block as the tail block (should be successful) */
 	ret = erofs_bh_balloon(bh, EROFS_BLKSIZ);
-	DBG_BUGON(ret);
+	DBG_BUGON(ret < 0);
 	return 0;
 }

--
2.30.0



More information about the Linux-erofs mailing list