Skip to content

Commit

Permalink
nilfs2: fix missing cleanup on rollforward recovery error
Browse files Browse the repository at this point in the history
In an error injection test of a routine for mount-time recovery, KASAN
found a use-after-free bug.

It turned out that if data recovery was performed using partial logs
created by dsync writes, but an error occurred before starting the log
writer to create a recovered checkpoint, the inodes whose data had been
recovered were left in the ns_dirty_files list of the nilfs object and
were not freed.

Fix this issue by cleaning up inodes that have read the recovery data if
the recovery routine fails midway before the log writer starts.

Link: https://lkml.kernel.org/r/[email protected]
Fixes: 0f3e1c7 ("nilfs2: recovery functions")
Signed-off-by: Ryusuke Konishi <[email protected]>
Tested-by: Ryusuke Konishi <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
  • Loading branch information
konis authored and akpm00 committed Sep 2, 2024
1 parent 6834082 commit 5787fca
Showing 1 changed file with 33 additions and 2 deletions.
35 changes: 33 additions & 2 deletions fs/nilfs2/recovery.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,6 +715,33 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
brelse(bh);
}

/**
* nilfs_abort_roll_forward - cleaning up after a failed rollforward recovery
* @nilfs: nilfs object
*/
static void nilfs_abort_roll_forward(struct the_nilfs *nilfs)
{
struct nilfs_inode_info *ii, *n;
LIST_HEAD(head);

/* Abandon inodes that have read recovery data */
spin_lock(&nilfs->ns_inode_lock);
list_splice_init(&nilfs->ns_dirty_files, &head);
spin_unlock(&nilfs->ns_inode_lock);
if (list_empty(&head))
return;

set_nilfs_purging(nilfs);
list_for_each_entry_safe(ii, n, &head, i_dirty) {
spin_lock(&nilfs->ns_inode_lock);
list_del_init(&ii->i_dirty);
spin_unlock(&nilfs->ns_inode_lock);

iput(&ii->vfs_inode);
}
clear_nilfs_purging(nilfs);
}

/**
* nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
* @nilfs: nilfs object
Expand Down Expand Up @@ -773,15 +800,19 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
if (unlikely(err)) {
nilfs_err(sb, "error %d writing segment for recovery",
err);
goto failed;
goto put_root;
}

nilfs_finish_roll_forward(nilfs, ri);
}

failed:
put_root:
nilfs_put_root(root);
return err;

failed:
nilfs_abort_roll_forward(nilfs);
goto put_root;
}

/**
Expand Down

0 comments on commit 5787fca

Please sign in to comment.