From: Gao Xiang <gaoxian...@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 <gaoxian...@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

Reply via email to