[PATCH 13/13] erofs-utils: fix potential erofs_bh_balloon failure
Gao Xiang
hsiangkao at aol.com
Fri May 31 10:50:47 AEST 2019
From: Gao Xiang <gaoxiang25 at huawei.com>
erofs_write_tail_end is called at the last end
of erofs_mkfs_build_tree, which is of course
after traversing all sub-tree inodes.
Therefore, erofs_bh_balloon could fail if
corresponding block is allocated, fix it.
Signed-off-by: Gao Xiang <gaoxiang25 at huawei.com>
---
Will be wrapped in the original patch.
lib/inode.c | 61 +++++++++++++++++++++++++++++++++++------------------
1 file changed, 40 insertions(+), 21 deletions(-)
diff --git a/lib/inode.c b/lib/inode.c
index b7fcf0e..9f7a4e4 100644
--- a/lib/inode.c
+++ b/lib/inode.c
@@ -399,6 +399,35 @@ static struct erofs_bhops erofs_write_inode_bhops = {
.flush = erofs_bh_flush_write_inode,
};
+int erofs_prepare_tail_block(struct erofs_inode *inode)
+{
+ struct erofs_buffer_head *bh;
+ int ret;
+
+ if (!inode->idata_size)
+ return 0;
+
+ bh = inode->bh_data;
+ if (!bh) {
+ bh = erofs_balloc(DATA, EROFS_BLKSIZ, 0, 0);
+ if (IS_ERR(bh))
+ return PTR_ERR(bh);
+ bh->op = &erofs_skip_write_bhops;
+
+ /* get blkaddr of bh */
+ ret = erofs_mapbh(bh->block, true);
+ DBG_BUGON(ret < 0);
+ inode->u.i_blkaddr = bh->block->blkaddr;
+
+ inode->bh_data = bh;
+ return 0;
+ }
+ /* expend a block as the tail block (should be successful) */
+ ret = erofs_bh_balloon(bh, EROFS_BLKSIZ);
+ DBG_BUGON(ret);
+ return 0;
+}
+
int erofs_prepare_inode_buffer(struct erofs_inode *inode)
{
unsigned int inodesize;
@@ -421,11 +450,18 @@ int erofs_prepare_inode_buffer(struct erofs_inode *inode)
bh = erofs_balloc(INODE, inodesize, 0, inode->idata_size);
if (bh == ERR_PTR(-ENOSPC)) {
+ int ret;
+
inode->data_mapping_mode = EROFS_INODE_LAYOUT_PLAIN;
noinline:
+ /* expend an extra block for tail-end data */
+ ret = erofs_prepare_tail_block(inode);
+ if (ret)
+ return ret;
bh = erofs_balloc(INODE, inodesize, 0, 0);
if (IS_ERR(bh))
return PTR_ERR(bh);
+ DBG_BUGON(inode->bh_inline);
} else if (IS_ERR(bh)) {
return PTR_ERR(bh);
} else if (inode->idata_size) {
@@ -485,28 +521,11 @@ int erofs_write_tail_end(struct erofs_inode *inode)
ibh->op = &erofs_write_inline_bhops;
} else {
int ret;
- erofs_off_t off;
-
- if (bh) {
- /* expend a block (should be successful) */
- ret = erofs_bh_balloon(bh, EROFS_BLKSIZ);
- DBG_BUGON(ret);
-
- erofs_mapbh(bh->block, true);
- off = erofs_btell(bh, true) - EROFS_BLKSIZ;
- } else {
- bh = erofs_balloc(DATA, EROFS_BLKSIZ, 0, 0);
- if (IS_ERR(bh))
- return PTR_ERR(bh);
-
- bh->op = &erofs_skip_write_bhops;
- erofs_mapbh(bh->block, true);
- off = erofs_btell(bh, false);
- inode->u.i_blkaddr = erofs_blknr(off);
- inode->bh_data = bh;
- }
- ret = dev_write(inode->idata, off, inode->idata_size);
+ erofs_mapbh(bh->block, true);
+ ret = dev_write(inode->idata,
+ erofs_btell(bh, true) - EROFS_BLKSIZ,
+ inode->idata_size);
if (ret)
return ret;
--
2.17.1
More information about the Linux-erofs
mailing list