In truncate_inode_blocks, we can get some stale node block addresses in
the following scenario.

1. ipage = get_node_page(ino)
2. unlock_page(ipage)
3. trundate_dnode()
 - invalidates all the data indices
 - truncate node block
4. lock_page(ipage) and then failed, goto restart
5. -ENOMEM or -EIO between #1 and #3

In this case, we already invalidate node block, but its indirect block still
has its nid.

Signed-off-by: Jaegeuk Kim <jaeg...@kernel.org>
---
 fs/f2fs/node.c | 12 +++---------
 1 file changed, 3 insertions(+), 9 deletions(-)

diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 118321b..780ce68 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -832,7 +832,7 @@ int truncate_inode_blocks(struct inode *inode, pgoff_t from)
        trace_f2fs_truncate_inode_blocks_enter(inode, from);
 
        level = get_node_path(inode, from, offset, noffset);
-restart:
+
        page = get_node_page(sbi, inode->i_ino);
        if (IS_ERR(page)) {
                trace_f2fs_truncate_inode_blocks_exit(inode, PTR_ERR(page));
@@ -840,7 +840,7 @@ restart:
        }
 
        set_new_dnode(&dn, inode, page, NULL, 0);
-       unlock_page(page);
+       dn.inode_page_locked = true;
 
        ri = F2FS_INODE(page);
        switch (level) {
@@ -895,22 +895,16 @@ skip_partial:
                        goto fail;
                if (offset[1] == 0 &&
                                ri->i_nid[offset[0] - NODE_DIR1_BLOCK]) {
-                       lock_page(page);
-                       if (unlikely(page->mapping != NODE_MAPPING(sbi))) {
-                               f2fs_put_page(page, 1);
-                               goto restart;
-                       }
                        f2fs_wait_on_page_writeback(page, NODE, true);
                        ri->i_nid[offset[0] - NODE_DIR1_BLOCK] = 0;
                        set_page_dirty(page);
-                       unlock_page(page);
                }
                offset[1] = 0;
                offset[0]++;
                nofs += err;
        }
 fail:
-       f2fs_put_page(page, 0);
+       f2fs_put_page(page, 1);
        trace_f2fs_truncate_inode_blocks_exit(inode, err);
        return err > 0 ? 0 : err;
 }
-- 
2.6.3

Reply via email to