Skip to content

Commit 5787fca

Browse files
konisakpm00
authored andcommitted
nilfs2: fix missing cleanup on rollforward recovery error
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]>
1 parent 6834082 commit 5787fca

File tree

1 file changed

+33
-2
lines changed

1 file changed

+33
-2
lines changed

fs/nilfs2/recovery.c

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -715,6 +715,33 @@ static void nilfs_finish_roll_forward(struct the_nilfs *nilfs,
715715
brelse(bh);
716716
}
717717

718+
/**
719+
* nilfs_abort_roll_forward - cleaning up after a failed rollforward recovery
720+
* @nilfs: nilfs object
721+
*/
722+
static void nilfs_abort_roll_forward(struct the_nilfs *nilfs)
723+
{
724+
struct nilfs_inode_info *ii, *n;
725+
LIST_HEAD(head);
726+
727+
/* Abandon inodes that have read recovery data */
728+
spin_lock(&nilfs->ns_inode_lock);
729+
list_splice_init(&nilfs->ns_dirty_files, &head);
730+
spin_unlock(&nilfs->ns_inode_lock);
731+
if (list_empty(&head))
732+
return;
733+
734+
set_nilfs_purging(nilfs);
735+
list_for_each_entry_safe(ii, n, &head, i_dirty) {
736+
spin_lock(&nilfs->ns_inode_lock);
737+
list_del_init(&ii->i_dirty);
738+
spin_unlock(&nilfs->ns_inode_lock);
739+
740+
iput(&ii->vfs_inode);
741+
}
742+
clear_nilfs_purging(nilfs);
743+
}
744+
718745
/**
719746
* nilfs_salvage_orphan_logs - salvage logs written after the latest checkpoint
720747
* @nilfs: nilfs object
@@ -773,15 +800,19 @@ int nilfs_salvage_orphan_logs(struct the_nilfs *nilfs,
773800
if (unlikely(err)) {
774801
nilfs_err(sb, "error %d writing segment for recovery",
775802
err);
776-
goto failed;
803+
goto put_root;
777804
}
778805

779806
nilfs_finish_roll_forward(nilfs, ri);
780807
}
781808

782-
failed:
809+
put_root:
783810
nilfs_put_root(root);
784811
return err;
812+
813+
failed:
814+
nilfs_abort_roll_forward(nilfs);
815+
goto put_root;
785816
}
786817

787818
/**

0 commit comments

Comments
 (0)