10a8165d7SJaegeuk Kim /* 2d624c96fSJaegeuk Kim * fs/f2fs/recovery.c 3d624c96fSJaegeuk Kim * 4d624c96fSJaegeuk Kim * Copyright (c) 2012 Samsung Electronics Co., Ltd. 5d624c96fSJaegeuk Kim * http://www.samsung.com/ 6d624c96fSJaegeuk Kim * 7d624c96fSJaegeuk Kim * This program is free software; you can redistribute it and/or modify 8d624c96fSJaegeuk Kim * it under the terms of the GNU General Public License version 2 as 9d624c96fSJaegeuk Kim * published by the Free Software Foundation. 10d624c96fSJaegeuk Kim */ 11d624c96fSJaegeuk Kim #include <linux/fs.h> 12d624c96fSJaegeuk Kim #include <linux/f2fs_fs.h> 13d624c96fSJaegeuk Kim #include "f2fs.h" 14d624c96fSJaegeuk Kim #include "node.h" 15d624c96fSJaegeuk Kim #include "segment.h" 16d624c96fSJaegeuk Kim 17d624c96fSJaegeuk Kim static struct kmem_cache *fsync_entry_slab; 18d624c96fSJaegeuk Kim 19d624c96fSJaegeuk Kim bool space_for_roll_forward(struct f2fs_sb_info *sbi) 20d624c96fSJaegeuk Kim { 21d624c96fSJaegeuk Kim if (sbi->last_valid_block_count + sbi->alloc_valid_block_count 22d624c96fSJaegeuk Kim > sbi->user_block_count) 23d624c96fSJaegeuk Kim return false; 24d624c96fSJaegeuk Kim return true; 25d624c96fSJaegeuk Kim } 26d624c96fSJaegeuk Kim 27d624c96fSJaegeuk Kim static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, 28d624c96fSJaegeuk Kim nid_t ino) 29d624c96fSJaegeuk Kim { 30d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 31d624c96fSJaegeuk Kim 322d7b822aSChao Yu list_for_each_entry(entry, head, list) 33d624c96fSJaegeuk Kim if (entry->inode->i_ino == ino) 34d624c96fSJaegeuk Kim return entry; 352d7b822aSChao Yu 36d624c96fSJaegeuk Kim return NULL; 37d624c96fSJaegeuk Kim } 38d624c96fSJaegeuk Kim 39d624c96fSJaegeuk Kim static int recover_dentry(struct page *ipage, struct inode *inode) 40d624c96fSJaegeuk Kim { 4158bfaf44SJaegeuk Kim struct f2fs_inode *raw_inode = F2FS_INODE(ipage); 4274d0b917SJaegeuk Kim nid_t pino = le32_to_cpu(raw_inode->i_pino); 436b8213d9SJaegeuk Kim struct f2fs_dir_entry *de; 44b7f7a5e0SAl Viro struct qstr name; 45d624c96fSJaegeuk Kim struct page *page; 466b8213d9SJaegeuk Kim struct inode *dir, *einode; 47d624c96fSJaegeuk Kim int err = 0; 48d624c96fSJaegeuk Kim 4974d0b917SJaegeuk Kim dir = f2fs_iget(inode->i_sb, pino); 50d624c96fSJaegeuk Kim if (IS_ERR(dir)) { 51047184b4SChris Fries err = PTR_ERR(dir); 52d624c96fSJaegeuk Kim goto out; 53d624c96fSJaegeuk Kim } 54ed57c27fSJaegeuk Kim 55ed57c27fSJaegeuk Kim if (is_inode_flag_set(F2FS_I(dir), FI_DIRTY_DIR)) { 56ed57c27fSJaegeuk Kim iput(dir); 57ed57c27fSJaegeuk Kim } else { 585deb8267SJaegeuk Kim add_dirty_dir_inode(dir); 59ed57c27fSJaegeuk Kim set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); 6074d0b917SJaegeuk Kim } 61d624c96fSJaegeuk Kim 62b7f7a5e0SAl Viro name.len = le32_to_cpu(raw_inode->i_namelen); 63b7f7a5e0SAl Viro name.name = raw_inode->i_name; 64d96b1431SChao Yu 65d96b1431SChao Yu if (unlikely(name.len > F2FS_NAME_LEN)) { 66d96b1431SChao Yu WARN_ON(1); 67d96b1431SChao Yu err = -ENAMETOOLONG; 68d96b1431SChao Yu goto out; 69d96b1431SChao Yu } 706b8213d9SJaegeuk Kim retry: 716b8213d9SJaegeuk Kim de = f2fs_find_entry(dir, &name, &page); 722e5558f4SRuss W. Knize if (de && inode->i_ino == le32_to_cpu(de->ino)) 732e5558f4SRuss W. Knize goto out_unmap_put; 746b8213d9SJaegeuk Kim if (de) { 756b8213d9SJaegeuk Kim einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); 766b8213d9SJaegeuk Kim if (IS_ERR(einode)) { 776b8213d9SJaegeuk Kim WARN_ON(1); 786b8213d9SJaegeuk Kim if (PTR_ERR(einode) == -ENOENT) 796b8213d9SJaegeuk Kim err = -EEXIST; 802e5558f4SRuss W. Knize goto out_unmap_put; 812e5558f4SRuss W. Knize } 822e5558f4SRuss W. Knize err = acquire_orphan_inode(F2FS_SB(inode->i_sb)); 832e5558f4SRuss W. Knize if (err) { 842e5558f4SRuss W. Knize iput(einode); 852e5558f4SRuss W. Knize goto out_unmap_put; 866b8213d9SJaegeuk Kim } 876b8213d9SJaegeuk Kim f2fs_delete_entry(de, page, einode); 886b8213d9SJaegeuk Kim iput(einode); 896b8213d9SJaegeuk Kim goto retry; 906b8213d9SJaegeuk Kim } 916b8213d9SJaegeuk Kim err = __f2fs_add_link(dir, &name, inode); 922e5558f4SRuss W. Knize goto out; 932e5558f4SRuss W. Knize 942e5558f4SRuss W. Knize out_unmap_put: 952e5558f4SRuss W. Knize kunmap(page); 962e5558f4SRuss W. Knize f2fs_put_page(page, 0); 97d624c96fSJaegeuk Kim out: 986c311ec6SChris Fries f2fs_msg(inode->i_sb, KERN_NOTICE, 996c311ec6SChris Fries "%s: ino = %x, name = %s, dir = %lx, err = %d", 1006c311ec6SChris Fries __func__, ino_of_node(ipage), raw_inode->i_name, 101f28c06faSDan Carpenter IS_ERR(dir) ? 0 : dir->i_ino, err); 102d624c96fSJaegeuk Kim return err; 103d624c96fSJaegeuk Kim } 104d624c96fSJaegeuk Kim 105d624c96fSJaegeuk Kim static int recover_inode(struct inode *inode, struct page *node_page) 106d624c96fSJaegeuk Kim { 10758bfaf44SJaegeuk Kim struct f2fs_inode *raw_inode = F2FS_INODE(node_page); 108d624c96fSJaegeuk Kim 109f356fe0cSJaegeuk Kim if (!IS_INODE(node_page)) 110f356fe0cSJaegeuk Kim return 0; 111f356fe0cSJaegeuk Kim 11225ca923bSJaegeuk Kim inode->i_mode = le16_to_cpu(raw_inode->i_mode); 113d624c96fSJaegeuk Kim i_size_write(inode, le64_to_cpu(raw_inode->i_size)); 114d624c96fSJaegeuk Kim inode->i_atime.tv_sec = le64_to_cpu(raw_inode->i_mtime); 115d624c96fSJaegeuk Kim inode->i_ctime.tv_sec = le64_to_cpu(raw_inode->i_ctime); 116d624c96fSJaegeuk Kim inode->i_mtime.tv_sec = le64_to_cpu(raw_inode->i_mtime); 117d624c96fSJaegeuk Kim inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); 118d624c96fSJaegeuk Kim inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec); 119d624c96fSJaegeuk Kim inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec); 120d624c96fSJaegeuk Kim 121f356fe0cSJaegeuk Kim if (is_dent_dnode(node_page)) 122d624c96fSJaegeuk Kim return recover_dentry(node_page, inode); 123f356fe0cSJaegeuk Kim 124f356fe0cSJaegeuk Kim f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s", 125f356fe0cSJaegeuk Kim ino_of_node(node_page), raw_inode->i_name); 126f356fe0cSJaegeuk Kim return 0; 127d624c96fSJaegeuk Kim } 128d624c96fSJaegeuk Kim 129d624c96fSJaegeuk Kim static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) 130d624c96fSJaegeuk Kim { 131d71b5564SJaegeuk Kim unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 132d624c96fSJaegeuk Kim struct curseg_info *curseg; 133d624c96fSJaegeuk Kim struct page *page; 134d624c96fSJaegeuk Kim block_t blkaddr; 135d624c96fSJaegeuk Kim int err = 0; 136d624c96fSJaegeuk Kim 137d624c96fSJaegeuk Kim /* get node pages in the current segment */ 138d624c96fSJaegeuk Kim curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); 139695fd1edSChao Yu blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 140d624c96fSJaegeuk Kim 141d624c96fSJaegeuk Kim /* read node page */ 142d624c96fSJaegeuk Kim page = alloc_page(GFP_F2FS_ZERO); 143e27dae4dSDan Carpenter if (!page) 144e27dae4dSDan Carpenter return -ENOMEM; 145d624c96fSJaegeuk Kim lock_page(page); 146d624c96fSJaegeuk Kim 147d624c96fSJaegeuk Kim while (1) { 148d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 149d624c96fSJaegeuk Kim 15093dfe2acSJaegeuk Kim err = f2fs_submit_page_bio(sbi, page, blkaddr, READ_SYNC); 151393ff91fSJaegeuk Kim if (err) 152b9987a27SChao Yu return err; 153d624c96fSJaegeuk Kim 154393ff91fSJaegeuk Kim lock_page(page); 155393ff91fSJaegeuk Kim 1566ead1142SJaegeuk Kim if (cp_ver != cpver_of_node(page)) 157f356fe0cSJaegeuk Kim break; 158d624c96fSJaegeuk Kim 159d624c96fSJaegeuk Kim if (!is_fsync_dnode(page)) 160d624c96fSJaegeuk Kim goto next; 161d624c96fSJaegeuk Kim 162d624c96fSJaegeuk Kim entry = get_fsync_inode(head, ino_of_node(page)); 163d624c96fSJaegeuk Kim if (entry) { 164d624c96fSJaegeuk Kim if (IS_INODE(page) && is_dent_dnode(page)) 165d624c96fSJaegeuk Kim set_inode_flag(F2FS_I(entry->inode), 166d624c96fSJaegeuk Kim FI_INC_LINK); 167d624c96fSJaegeuk Kim } else { 168d624c96fSJaegeuk Kim if (IS_INODE(page) && is_dent_dnode(page)) { 1696ead1142SJaegeuk Kim err = recover_inode_page(sbi, page); 1706ead1142SJaegeuk Kim if (err) 171f356fe0cSJaegeuk Kim break; 172d624c96fSJaegeuk Kim } 173d624c96fSJaegeuk Kim 174d624c96fSJaegeuk Kim /* add this fsync inode to the list */ 175d624c96fSJaegeuk Kim entry = kmem_cache_alloc(fsync_entry_slab, GFP_NOFS); 176d624c96fSJaegeuk Kim if (!entry) { 177d624c96fSJaegeuk Kim err = -ENOMEM; 178f356fe0cSJaegeuk Kim break; 179d624c96fSJaegeuk Kim } 180d624c96fSJaegeuk Kim 181d624c96fSJaegeuk Kim entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); 182d624c96fSJaegeuk Kim if (IS_ERR(entry->inode)) { 183d624c96fSJaegeuk Kim err = PTR_ERR(entry->inode); 184fd8bb65fSNamjae Jeon kmem_cache_free(fsync_entry_slab, entry); 185f356fe0cSJaegeuk Kim break; 186d624c96fSJaegeuk Kim } 187fd8bb65fSNamjae Jeon list_add_tail(&entry->list, head); 188d624c96fSJaegeuk Kim } 189addbe45bSJaegeuk Kim entry->blkaddr = blkaddr; 190addbe45bSJaegeuk Kim 191d624c96fSJaegeuk Kim err = recover_inode(entry->inode, page); 192f356fe0cSJaegeuk Kim if (err && err != -ENOENT) 193f356fe0cSJaegeuk Kim break; 194d624c96fSJaegeuk Kim next: 195d624c96fSJaegeuk Kim /* check next segment */ 196d624c96fSJaegeuk Kim blkaddr = next_blkaddr_of_node(page); 197d624c96fSJaegeuk Kim } 198b9987a27SChao Yu 199d624c96fSJaegeuk Kim unlock_page(page); 200d624c96fSJaegeuk Kim __free_pages(page, 0); 201b9987a27SChao Yu 202d624c96fSJaegeuk Kim return err; 203d624c96fSJaegeuk Kim } 204d624c96fSJaegeuk Kim 2055ebefc5bSGu Zheng static void destroy_fsync_dnodes(struct list_head *head) 206d624c96fSJaegeuk Kim { 207d8b79b2fSDan Carpenter struct fsync_inode_entry *entry, *tmp; 208d8b79b2fSDan Carpenter 209d8b79b2fSDan Carpenter list_for_each_entry_safe(entry, tmp, head, list) { 210d624c96fSJaegeuk Kim iput(entry->inode); 211d624c96fSJaegeuk Kim list_del(&entry->list); 212d624c96fSJaegeuk Kim kmem_cache_free(fsync_entry_slab, entry); 213d624c96fSJaegeuk Kim } 214d624c96fSJaegeuk Kim } 215d624c96fSJaegeuk Kim 21639cf72cfSJaegeuk Kim static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, 217b292dcabSJaegeuk Kim block_t blkaddr, struct dnode_of_data *dn) 218d624c96fSJaegeuk Kim { 219d624c96fSJaegeuk Kim struct seg_entry *sentry; 220d624c96fSJaegeuk Kim unsigned int segno = GET_SEGNO(sbi, blkaddr); 221491c0854SJaegeuk Kim unsigned short blkoff = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); 222f6517cfcSJaegeuk Kim struct f2fs_summary_block *sum_node; 223d624c96fSJaegeuk Kim struct f2fs_summary sum; 224f6517cfcSJaegeuk Kim struct page *sum_page, *node_page; 225b292dcabSJaegeuk Kim nid_t ino, nid; 226d624c96fSJaegeuk Kim struct inode *inode; 227de93653fSJaegeuk Kim unsigned int offset; 228d624c96fSJaegeuk Kim block_t bidx; 229d624c96fSJaegeuk Kim int i; 230d624c96fSJaegeuk Kim 231d624c96fSJaegeuk Kim sentry = get_seg_entry(sbi, segno); 232d624c96fSJaegeuk Kim if (!f2fs_test_bit(blkoff, sentry->cur_valid_map)) 23339cf72cfSJaegeuk Kim return 0; 234d624c96fSJaegeuk Kim 235d624c96fSJaegeuk Kim /* Get the previous summary */ 236d624c96fSJaegeuk Kim for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) { 237d624c96fSJaegeuk Kim struct curseg_info *curseg = CURSEG_I(sbi, i); 238d624c96fSJaegeuk Kim if (curseg->segno == segno) { 239d624c96fSJaegeuk Kim sum = curseg->sum_blk->entries[blkoff]; 240f6517cfcSJaegeuk Kim goto got_it; 241d624c96fSJaegeuk Kim } 242d624c96fSJaegeuk Kim } 243d624c96fSJaegeuk Kim 244f6517cfcSJaegeuk Kim sum_page = get_sum_page(sbi, segno); 245f6517cfcSJaegeuk Kim sum_node = (struct f2fs_summary_block *)page_address(sum_page); 246f6517cfcSJaegeuk Kim sum = sum_node->entries[blkoff]; 247f6517cfcSJaegeuk Kim f2fs_put_page(sum_page, 1); 248f6517cfcSJaegeuk Kim got_it: 249b292dcabSJaegeuk Kim /* Use the locked dnode page and inode */ 250b292dcabSJaegeuk Kim nid = le32_to_cpu(sum.nid); 251b292dcabSJaegeuk Kim if (dn->inode->i_ino == nid) { 252b292dcabSJaegeuk Kim struct dnode_of_data tdn = *dn; 253b292dcabSJaegeuk Kim tdn.nid = nid; 254b292dcabSJaegeuk Kim tdn.node_page = dn->inode_page; 255060dd67bSJaegeuk Kim tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 256b292dcabSJaegeuk Kim truncate_data_blocks_range(&tdn, 1); 25739cf72cfSJaegeuk Kim return 0; 258b292dcabSJaegeuk Kim } else if (dn->nid == nid) { 259b292dcabSJaegeuk Kim struct dnode_of_data tdn = *dn; 260060dd67bSJaegeuk Kim tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 261b292dcabSJaegeuk Kim truncate_data_blocks_range(&tdn, 1); 26239cf72cfSJaegeuk Kim return 0; 263b292dcabSJaegeuk Kim } 264b292dcabSJaegeuk Kim 265d624c96fSJaegeuk Kim /* Get the node page */ 266b292dcabSJaegeuk Kim node_page = get_node_page(sbi, nid); 26739cf72cfSJaegeuk Kim if (IS_ERR(node_page)) 26839cf72cfSJaegeuk Kim return PTR_ERR(node_page); 269de93653fSJaegeuk Kim 270de93653fSJaegeuk Kim offset = ofs_of_node(node_page); 271d624c96fSJaegeuk Kim ino = ino_of_node(node_page); 272d624c96fSJaegeuk Kim f2fs_put_page(node_page, 1); 273d624c96fSJaegeuk Kim 274d624c96fSJaegeuk Kim /* Deallocate previous index in the node page */ 275d4686d56SJaegeuk Kim inode = f2fs_iget(sbi->sb, ino); 27606025f4dSNamjae Jeon if (IS_ERR(inode)) 27739cf72cfSJaegeuk Kim return PTR_ERR(inode); 27806025f4dSNamjae Jeon 279de93653fSJaegeuk Kim bidx = start_bidx_of_node(offset, F2FS_I(inode)) + 280de93653fSJaegeuk Kim le16_to_cpu(sum.ofs_in_node); 281de93653fSJaegeuk Kim 282d624c96fSJaegeuk Kim truncate_hole(inode, bidx, bidx + 1); 283d624c96fSJaegeuk Kim iput(inode); 28439cf72cfSJaegeuk Kim return 0; 285d624c96fSJaegeuk Kim } 286d624c96fSJaegeuk Kim 2876ead1142SJaegeuk Kim static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, 288d624c96fSJaegeuk Kim struct page *page, block_t blkaddr) 289d624c96fSJaegeuk Kim { 290de93653fSJaegeuk Kim struct f2fs_inode_info *fi = F2FS_I(inode); 291d624c96fSJaegeuk Kim unsigned int start, end; 292d624c96fSJaegeuk Kim struct dnode_of_data dn; 293d624c96fSJaegeuk Kim struct f2fs_summary sum; 294d624c96fSJaegeuk Kim struct node_info ni; 295f356fe0cSJaegeuk Kim int err = 0, recovered = 0; 296d624c96fSJaegeuk Kim 2971e1bb4baSJaegeuk Kim if (recover_inline_data(inode, page)) 2981e1bb4baSJaegeuk Kim goto out; 2991e1bb4baSJaegeuk Kim 300abb2366cSJaegeuk Kim if (recover_xattr_data(inode, page, blkaddr)) 301abb2366cSJaegeuk Kim goto out; 302abb2366cSJaegeuk Kim 303de93653fSJaegeuk Kim start = start_bidx_of_node(ofs_of_node(page), fi); 3046403eb1fSChao Yu end = start + ADDRS_PER_PAGE(page, fi); 305d624c96fSJaegeuk Kim 306e479556bSGu Zheng f2fs_lock_op(sbi); 3071e1bb4baSJaegeuk Kim 308d624c96fSJaegeuk Kim set_new_dnode(&dn, inode, NULL, NULL, 0); 30939936837SJaegeuk Kim 3106ead1142SJaegeuk Kim err = get_dnode_of_data(&dn, start, ALLOC_NODE); 31139936837SJaegeuk Kim if (err) { 312e479556bSGu Zheng f2fs_unlock_op(sbi); 3131e1bb4baSJaegeuk Kim goto out; 31439936837SJaegeuk Kim } 315d624c96fSJaegeuk Kim 3163cb5ad15SJaegeuk Kim f2fs_wait_on_page_writeback(dn.node_page, NODE); 317d624c96fSJaegeuk Kim 318d624c96fSJaegeuk Kim get_node_info(sbi, dn.nid, &ni); 3195d56b671SJaegeuk Kim f2fs_bug_on(ni.ino != ino_of_node(page)); 3205d56b671SJaegeuk Kim f2fs_bug_on(ofs_of_node(dn.node_page) != ofs_of_node(page)); 321d624c96fSJaegeuk Kim 322d624c96fSJaegeuk Kim for (; start < end; start++) { 323d624c96fSJaegeuk Kim block_t src, dest; 324d624c96fSJaegeuk Kim 325d624c96fSJaegeuk Kim src = datablock_addr(dn.node_page, dn.ofs_in_node); 326d624c96fSJaegeuk Kim dest = datablock_addr(page, dn.ofs_in_node); 327d624c96fSJaegeuk Kim 328d624c96fSJaegeuk Kim if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) { 329d624c96fSJaegeuk Kim if (src == NULL_ADDR) { 3305d56b671SJaegeuk Kim err = reserve_new_block(&dn); 331d624c96fSJaegeuk Kim /* We should not get -ENOSPC */ 3325d56b671SJaegeuk Kim f2fs_bug_on(err); 333d624c96fSJaegeuk Kim } 334d624c96fSJaegeuk Kim 335d624c96fSJaegeuk Kim /* Check the previous node page having this index */ 33639cf72cfSJaegeuk Kim err = check_index_in_prev_nodes(sbi, dest, &dn); 33739cf72cfSJaegeuk Kim if (err) 33839cf72cfSJaegeuk Kim goto err; 339d624c96fSJaegeuk Kim 340d624c96fSJaegeuk Kim set_summary(&sum, dn.nid, dn.ofs_in_node, ni.version); 341d624c96fSJaegeuk Kim 342d624c96fSJaegeuk Kim /* write dummy data page */ 343d624c96fSJaegeuk Kim recover_data_page(sbi, NULL, &sum, src, dest); 344d624c96fSJaegeuk Kim update_extent_cache(dest, &dn); 345f356fe0cSJaegeuk Kim recovered++; 346d624c96fSJaegeuk Kim } 347d624c96fSJaegeuk Kim dn.ofs_in_node++; 348d624c96fSJaegeuk Kim } 349d624c96fSJaegeuk Kim 350d624c96fSJaegeuk Kim /* write node page in place */ 351d624c96fSJaegeuk Kim set_summary(&sum, dn.nid, 0, 0); 352d624c96fSJaegeuk Kim if (IS_INODE(dn.node_page)) 353d624c96fSJaegeuk Kim sync_inode_page(&dn); 354d624c96fSJaegeuk Kim 355d624c96fSJaegeuk Kim copy_node_footer(dn.node_page, page); 356d624c96fSJaegeuk Kim fill_node_footer(dn.node_page, dn.nid, ni.ino, 357d624c96fSJaegeuk Kim ofs_of_node(page), false); 358d624c96fSJaegeuk Kim set_page_dirty(dn.node_page); 359d624c96fSJaegeuk Kim 360d624c96fSJaegeuk Kim recover_node_page(sbi, dn.node_page, &sum, &ni, blkaddr); 36139cf72cfSJaegeuk Kim err: 362d624c96fSJaegeuk Kim f2fs_put_dnode(&dn); 363e479556bSGu Zheng f2fs_unlock_op(sbi); 3641e1bb4baSJaegeuk Kim out: 3656c311ec6SChris Fries f2fs_msg(sbi->sb, KERN_NOTICE, 3666c311ec6SChris Fries "recover_data: ino = %lx, recovered = %d blocks, err = %d", 36739cf72cfSJaegeuk Kim inode->i_ino, recovered, err); 36839cf72cfSJaegeuk Kim return err; 369d624c96fSJaegeuk Kim } 370d624c96fSJaegeuk Kim 3716ead1142SJaegeuk Kim static int recover_data(struct f2fs_sb_info *sbi, 372d624c96fSJaegeuk Kim struct list_head *head, int type) 373d624c96fSJaegeuk Kim { 374d71b5564SJaegeuk Kim unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 375d624c96fSJaegeuk Kim struct curseg_info *curseg; 376d624c96fSJaegeuk Kim struct page *page; 3776ead1142SJaegeuk Kim int err = 0; 378d624c96fSJaegeuk Kim block_t blkaddr; 379d624c96fSJaegeuk Kim 380d624c96fSJaegeuk Kim /* get node pages in the current segment */ 381d624c96fSJaegeuk Kim curseg = CURSEG_I(sbi, type); 382d624c96fSJaegeuk Kim blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 383d624c96fSJaegeuk Kim 384d624c96fSJaegeuk Kim /* read node page */ 385a0acdfe0SChao Yu page = alloc_page(GFP_F2FS_ZERO); 386e27dae4dSDan Carpenter if (!page) 3876ead1142SJaegeuk Kim return -ENOMEM; 3886ead1142SJaegeuk Kim 389d624c96fSJaegeuk Kim lock_page(page); 390d624c96fSJaegeuk Kim 391d624c96fSJaegeuk Kim while (1) { 392d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 393d624c96fSJaegeuk Kim 39493dfe2acSJaegeuk Kim err = f2fs_submit_page_bio(sbi, page, blkaddr, READ_SYNC); 3956ead1142SJaegeuk Kim if (err) 396b9987a27SChao Yu return err; 397d624c96fSJaegeuk Kim 398393ff91fSJaegeuk Kim lock_page(page); 399393ff91fSJaegeuk Kim 400d624c96fSJaegeuk Kim if (cp_ver != cpver_of_node(page)) 40145856affSJaegeuk Kim break; 402d624c96fSJaegeuk Kim 403d624c96fSJaegeuk Kim entry = get_fsync_inode(head, ino_of_node(page)); 404d624c96fSJaegeuk Kim if (!entry) 405d624c96fSJaegeuk Kim goto next; 406d624c96fSJaegeuk Kim 4076ead1142SJaegeuk Kim err = do_recover_data(sbi, entry->inode, page, blkaddr); 4086ead1142SJaegeuk Kim if (err) 40945856affSJaegeuk Kim break; 410d624c96fSJaegeuk Kim 411d624c96fSJaegeuk Kim if (entry->blkaddr == blkaddr) { 412d624c96fSJaegeuk Kim iput(entry->inode); 413d624c96fSJaegeuk Kim list_del(&entry->list); 414d624c96fSJaegeuk Kim kmem_cache_free(fsync_entry_slab, entry); 415d624c96fSJaegeuk Kim } 416d624c96fSJaegeuk Kim next: 417d624c96fSJaegeuk Kim /* check next segment */ 418d624c96fSJaegeuk Kim blkaddr = next_blkaddr_of_node(page); 419d624c96fSJaegeuk Kim } 420b9987a27SChao Yu 421d624c96fSJaegeuk Kim unlock_page(page); 422d624c96fSJaegeuk Kim __free_pages(page, 0); 423d624c96fSJaegeuk Kim 4246ead1142SJaegeuk Kim if (!err) 425d624c96fSJaegeuk Kim allocate_new_segments(sbi); 4266ead1142SJaegeuk Kim return err; 427d624c96fSJaegeuk Kim } 428d624c96fSJaegeuk Kim 4296ead1142SJaegeuk Kim int recover_fsync_data(struct f2fs_sb_info *sbi) 430d624c96fSJaegeuk Kim { 431d624c96fSJaegeuk Kim struct list_head inode_list; 4326ead1142SJaegeuk Kim int err; 433aabe5136SHaicheng Li bool need_writecp = false; 434d624c96fSJaegeuk Kim 435d624c96fSJaegeuk Kim fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", 436e8512d2eSGu Zheng sizeof(struct fsync_inode_entry)); 4376bacf52fSJaegeuk Kim if (!fsync_entry_slab) 4386ead1142SJaegeuk Kim return -ENOMEM; 439d624c96fSJaegeuk Kim 440d624c96fSJaegeuk Kim INIT_LIST_HEAD(&inode_list); 441d624c96fSJaegeuk Kim 442d624c96fSJaegeuk Kim /* step #1: find fsynced inode numbers */ 443aabe5136SHaicheng Li sbi->por_doing = true; 4446ead1142SJaegeuk Kim err = find_fsync_dnodes(sbi, &inode_list); 4456ead1142SJaegeuk Kim if (err) 446d624c96fSJaegeuk Kim goto out; 447d624c96fSJaegeuk Kim 448d624c96fSJaegeuk Kim if (list_empty(&inode_list)) 449d624c96fSJaegeuk Kim goto out; 450d624c96fSJaegeuk Kim 451aabe5136SHaicheng Li need_writecp = true; 452691c6fd2SChao Yu 453d624c96fSJaegeuk Kim /* step #2: recover data */ 4546ead1142SJaegeuk Kim err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); 4555d56b671SJaegeuk Kim f2fs_bug_on(!list_empty(&inode_list)); 456d624c96fSJaegeuk Kim out: 4575ebefc5bSGu Zheng destroy_fsync_dnodes(&inode_list); 458d624c96fSJaegeuk Kim kmem_cache_destroy(fsync_entry_slab); 459aabe5136SHaicheng Li sbi->por_doing = false; 460691c6fd2SChao Yu if (!err && need_writecp) 46143727527SJaegeuk Kim write_checkpoint(sbi, false); 4626ead1142SJaegeuk Kim return err; 463d624c96fSJaegeuk Kim } 464