|
@@ -99,8 +99,12 @@ err_out:
|
|
|
return ERR_PTR(err);
|
|
return ERR_PTR(err);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void del_fsync_inode(struct fsync_inode_entry *entry)
|
|
|
|
|
|
|
+static void del_fsync_inode(struct fsync_inode_entry *entry, int drop)
|
|
|
{
|
|
{
|
|
|
|
|
+ if (drop) {
|
|
|
|
|
+ /* inode should not be recovered, drop it */
|
|
|
|
|
+ f2fs_inode_synced(entry->inode);
|
|
|
|
|
+ }
|
|
|
iput(entry->inode);
|
|
iput(entry->inode);
|
|
|
list_del(&entry->list);
|
|
list_del(&entry->list);
|
|
|
kmem_cache_free(fsync_entry_slab, entry);
|
|
kmem_cache_free(fsync_entry_slab, entry);
|
|
@@ -321,12 +325,12 @@ next:
|
|
|
return err;
|
|
return err;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-static void destroy_fsync_dnodes(struct list_head *head)
|
|
|
|
|
|
|
+static void destroy_fsync_dnodes(struct list_head *head, int drop)
|
|
|
{
|
|
{
|
|
|
struct fsync_inode_entry *entry, *tmp;
|
|
struct fsync_inode_entry *entry, *tmp;
|
|
|
|
|
|
|
|
list_for_each_entry_safe(entry, tmp, head, list)
|
|
list_for_each_entry_safe(entry, tmp, head, list)
|
|
|
- del_fsync_inode(entry);
|
|
|
|
|
|
|
+ del_fsync_inode(entry, drop);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
|
static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
|
|
@@ -561,7 +565,7 @@ out:
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
|
static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
|
|
- struct list_head *dir_list)
|
|
|
|
|
|
|
+ struct list_head *tmp_inode_list, struct list_head *dir_list)
|
|
|
{
|
|
{
|
|
|
struct curseg_info *curseg;
|
|
struct curseg_info *curseg;
|
|
|
struct page *page = NULL;
|
|
struct page *page = NULL;
|
|
@@ -615,7 +619,7 @@ static int recover_data(struct f2fs_sb_info *sbi, struct list_head *inode_list,
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if (entry->blkaddr == blkaddr)
|
|
if (entry->blkaddr == blkaddr)
|
|
|
- del_fsync_inode(entry);
|
|
|
|
|
|
|
+ list_move_tail(&entry->list, tmp_inode_list);
|
|
|
next:
|
|
next:
|
|
|
/* check next segment */
|
|
/* check next segment */
|
|
|
blkaddr = next_blkaddr_of_node(page);
|
|
blkaddr = next_blkaddr_of_node(page);
|
|
@@ -628,7 +632,7 @@ next:
|
|
|
|
|
|
|
|
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
|
int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
|
|
{
|
|
{
|
|
|
- struct list_head inode_list;
|
|
|
|
|
|
|
+ struct list_head inode_list, tmp_inode_list;
|
|
|
struct list_head dir_list;
|
|
struct list_head dir_list;
|
|
|
int err;
|
|
int err;
|
|
|
int ret = 0;
|
|
int ret = 0;
|
|
@@ -659,6 +663,7 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
INIT_LIST_HEAD(&inode_list);
|
|
INIT_LIST_HEAD(&inode_list);
|
|
|
|
|
+ INIT_LIST_HEAD(&tmp_inode_list);
|
|
|
INIT_LIST_HEAD(&dir_list);
|
|
INIT_LIST_HEAD(&dir_list);
|
|
|
|
|
|
|
|
/* prevent checkpoint */
|
|
/* prevent checkpoint */
|
|
@@ -677,11 +682,16 @@ int f2fs_recover_fsync_data(struct f2fs_sb_info *sbi, bool check_only)
|
|
|
need_writecp = true;
|
|
need_writecp = true;
|
|
|
|
|
|
|
|
/* step #2: recover data */
|
|
/* step #2: recover data */
|
|
|
- err = recover_data(sbi, &inode_list, &dir_list);
|
|
|
|
|
|
|
+ err = recover_data(sbi, &inode_list, &tmp_inode_list, &dir_list);
|
|
|
if (!err)
|
|
if (!err)
|
|
|
f2fs_bug_on(sbi, !list_empty(&inode_list));
|
|
f2fs_bug_on(sbi, !list_empty(&inode_list));
|
|
|
|
|
+ else {
|
|
|
|
|
+ /* restore s_flags to let iput() trash data */
|
|
|
|
|
+ sbi->sb->s_flags = s_flags;
|
|
|
|
|
+ }
|
|
|
skip:
|
|
skip:
|
|
|
- destroy_fsync_dnodes(&inode_list);
|
|
|
|
|
|
|
+ destroy_fsync_dnodes(&inode_list, err);
|
|
|
|
|
+ destroy_fsync_dnodes(&tmp_inode_list, err);
|
|
|
|
|
|
|
|
/* truncate meta pages to be used by the recovery */
|
|
/* truncate meta pages to be used by the recovery */
|
|
|
truncate_inode_pages_range(META_MAPPING(sbi),
|
|
truncate_inode_pages_range(META_MAPPING(sbi),
|
|
@@ -690,13 +700,13 @@ skip:
|
|
|
if (err) {
|
|
if (err) {
|
|
|
truncate_inode_pages_final(NODE_MAPPING(sbi));
|
|
truncate_inode_pages_final(NODE_MAPPING(sbi));
|
|
|
truncate_inode_pages_final(META_MAPPING(sbi));
|
|
truncate_inode_pages_final(META_MAPPING(sbi));
|
|
|
|
|
+ } else {
|
|
|
|
|
+ clear_sbi_flag(sbi, SBI_POR_DOING);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- clear_sbi_flag(sbi, SBI_POR_DOING);
|
|
|
|
|
mutex_unlock(&sbi->cp_mutex);
|
|
mutex_unlock(&sbi->cp_mutex);
|
|
|
|
|
|
|
|
/* let's drop all the directory inodes for clean checkpoint */
|
|
/* let's drop all the directory inodes for clean checkpoint */
|
|
|
- destroy_fsync_dnodes(&dir_list);
|
|
|
|
|
|
|
+ destroy_fsync_dnodes(&dir_list, err);
|
|
|
|
|
|
|
|
if (need_writecp) {
|
|
if (need_writecp) {
|
|
|
set_sbi_flag(sbi, SBI_IS_RECOVERED);
|
|
set_sbi_flag(sbi, SBI_IS_RECOVERED);
|