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 17441ac5cbSJaegeuk Kim /* 18441ac5cbSJaegeuk Kim * Roll forward recovery scenarios. 19441ac5cbSJaegeuk Kim * 20441ac5cbSJaegeuk Kim * [Term] F: fsync_mark, D: dentry_mark 21441ac5cbSJaegeuk Kim * 22441ac5cbSJaegeuk Kim * 1. inode(x) | CP | inode(x) | dnode(F) 23441ac5cbSJaegeuk Kim * -> Update the latest inode(x). 24441ac5cbSJaegeuk Kim * 25441ac5cbSJaegeuk Kim * 2. inode(x) | CP | inode(F) | dnode(F) 26441ac5cbSJaegeuk Kim * -> No problem. 27441ac5cbSJaegeuk Kim * 28441ac5cbSJaegeuk Kim * 3. inode(x) | CP | dnode(F) | inode(x) 29441ac5cbSJaegeuk Kim * -> Recover to the latest dnode(F), and drop the last inode(x) 30441ac5cbSJaegeuk Kim * 31441ac5cbSJaegeuk Kim * 4. inode(x) | CP | dnode(F) | inode(F) 32441ac5cbSJaegeuk Kim * -> No problem. 33441ac5cbSJaegeuk Kim * 34441ac5cbSJaegeuk Kim * 5. CP | inode(x) | dnode(F) 35441ac5cbSJaegeuk Kim * -> The inode(DF) was missing. Should drop this dnode(F). 36441ac5cbSJaegeuk Kim * 37441ac5cbSJaegeuk Kim * 6. CP | inode(DF) | dnode(F) 38441ac5cbSJaegeuk Kim * -> No problem. 39441ac5cbSJaegeuk Kim * 40441ac5cbSJaegeuk Kim * 7. CP | dnode(F) | inode(DF) 41441ac5cbSJaegeuk Kim * -> If f2fs_iget fails, then goto next to find inode(DF). 42441ac5cbSJaegeuk Kim * 43441ac5cbSJaegeuk Kim * 8. CP | dnode(F) | inode(x) 44441ac5cbSJaegeuk Kim * -> If f2fs_iget fails, then goto next to find inode(DF). 45441ac5cbSJaegeuk Kim * But it will fail due to no inode(DF). 46441ac5cbSJaegeuk Kim */ 47441ac5cbSJaegeuk Kim 48d624c96fSJaegeuk Kim static struct kmem_cache *fsync_entry_slab; 49d624c96fSJaegeuk Kim 50d624c96fSJaegeuk Kim bool space_for_roll_forward(struct f2fs_sb_info *sbi) 51d624c96fSJaegeuk Kim { 52d624c96fSJaegeuk Kim if (sbi->last_valid_block_count + sbi->alloc_valid_block_count 53d624c96fSJaegeuk Kim > sbi->user_block_count) 54d624c96fSJaegeuk Kim return false; 55d624c96fSJaegeuk Kim return true; 56d624c96fSJaegeuk Kim } 57d624c96fSJaegeuk Kim 58d624c96fSJaegeuk Kim static struct fsync_inode_entry *get_fsync_inode(struct list_head *head, 59d624c96fSJaegeuk Kim nid_t ino) 60d624c96fSJaegeuk Kim { 61d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 62d624c96fSJaegeuk Kim 632d7b822aSChao Yu list_for_each_entry(entry, head, list) 64d624c96fSJaegeuk Kim if (entry->inode->i_ino == ino) 65d624c96fSJaegeuk Kim return entry; 662d7b822aSChao Yu 67d624c96fSJaegeuk Kim return NULL; 68d624c96fSJaegeuk Kim } 69d624c96fSJaegeuk Kim 70c52e1b10SJaegeuk Kim static int recover_dentry(struct inode *inode, struct page *ipage) 71d624c96fSJaegeuk Kim { 7258bfaf44SJaegeuk Kim struct f2fs_inode *raw_inode = F2FS_INODE(ipage); 7374d0b917SJaegeuk Kim nid_t pino = le32_to_cpu(raw_inode->i_pino); 746b8213d9SJaegeuk Kim struct f2fs_dir_entry *de; 75b7f7a5e0SAl Viro struct qstr name; 76d624c96fSJaegeuk Kim struct page *page; 776b8213d9SJaegeuk Kim struct inode *dir, *einode; 78d624c96fSJaegeuk Kim int err = 0; 79d624c96fSJaegeuk Kim 8074d0b917SJaegeuk Kim dir = f2fs_iget(inode->i_sb, pino); 81d624c96fSJaegeuk Kim if (IS_ERR(dir)) { 82047184b4SChris Fries err = PTR_ERR(dir); 83d624c96fSJaegeuk Kim goto out; 84d624c96fSJaegeuk Kim } 85ed57c27fSJaegeuk Kim 86e7d55452SJaegeuk Kim if (file_enc_name(inode)) { 87e7d55452SJaegeuk Kim iput(dir); 88e7d55452SJaegeuk Kim return 0; 89e7d55452SJaegeuk Kim } 90e7d55452SJaegeuk Kim 91b7f7a5e0SAl Viro name.len = le32_to_cpu(raw_inode->i_namelen); 92b7f7a5e0SAl Viro name.name = raw_inode->i_name; 93d96b1431SChao Yu 94d96b1431SChao Yu if (unlikely(name.len > F2FS_NAME_LEN)) { 95d96b1431SChao Yu WARN_ON(1); 96d96b1431SChao Yu err = -ENAMETOOLONG; 9786928f98SJaegeuk Kim goto out_err; 98d96b1431SChao Yu } 996b8213d9SJaegeuk Kim retry: 1006b8213d9SJaegeuk Kim de = f2fs_find_entry(dir, &name, &page); 101418f6c27SJaegeuk Kim if (de && inode->i_ino == le32_to_cpu(de->ino)) 1022e5558f4SRuss W. Knize goto out_unmap_put; 103418f6c27SJaegeuk Kim 1046b8213d9SJaegeuk Kim if (de) { 1056b8213d9SJaegeuk Kim einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); 1066b8213d9SJaegeuk Kim if (IS_ERR(einode)) { 1076b8213d9SJaegeuk Kim WARN_ON(1); 1085c1f9927SChao Yu err = PTR_ERR(einode); 1095c1f9927SChao Yu if (err == -ENOENT) 1106b8213d9SJaegeuk Kim err = -EEXIST; 1112e5558f4SRuss W. Knize goto out_unmap_put; 1122e5558f4SRuss W. Knize } 1134081363fSJaegeuk Kim err = acquire_orphan_inode(F2FS_I_SB(inode)); 1142e5558f4SRuss W. Knize if (err) { 1152e5558f4SRuss W. Knize iput(einode); 1162e5558f4SRuss W. Knize goto out_unmap_put; 1176b8213d9SJaegeuk Kim } 118dbeacf02SChao Yu f2fs_delete_entry(de, page, dir, einode); 1196b8213d9SJaegeuk Kim iput(einode); 1206b8213d9SJaegeuk Kim goto retry; 1216b8213d9SJaegeuk Kim } 122510022a8SJaegeuk Kim err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); 12386928f98SJaegeuk Kim if (err) 12486928f98SJaegeuk Kim goto out_err; 12586928f98SJaegeuk Kim 12686928f98SJaegeuk Kim if (is_inode_flag_set(F2FS_I(dir), FI_DELAY_IPUT)) { 12786928f98SJaegeuk Kim iput(dir); 12886928f98SJaegeuk Kim } else { 12986928f98SJaegeuk Kim add_dirty_dir_inode(dir); 13086928f98SJaegeuk Kim set_inode_flag(F2FS_I(dir), FI_DELAY_IPUT); 13186928f98SJaegeuk Kim } 13286928f98SJaegeuk Kim 1332e5558f4SRuss W. Knize goto out; 1342e5558f4SRuss W. Knize 1352e5558f4SRuss W. Knize out_unmap_put: 1369486ba44SJaegeuk Kim f2fs_dentry_kunmap(dir, page); 1372e5558f4SRuss W. Knize f2fs_put_page(page, 0); 13886928f98SJaegeuk Kim out_err: 13986928f98SJaegeuk Kim iput(dir); 140d624c96fSJaegeuk Kim out: 1416c311ec6SChris Fries f2fs_msg(inode->i_sb, KERN_NOTICE, 1426c311ec6SChris Fries "%s: ino = %x, name = %s, dir = %lx, err = %d", 1436c311ec6SChris Fries __func__, ino_of_node(ipage), raw_inode->i_name, 144f28c06faSDan Carpenter IS_ERR(dir) ? 0 : dir->i_ino, err); 145d624c96fSJaegeuk Kim return err; 146d624c96fSJaegeuk Kim } 147d624c96fSJaegeuk Kim 148c52e1b10SJaegeuk Kim static void recover_inode(struct inode *inode, struct page *page) 149441ac5cbSJaegeuk Kim { 150441ac5cbSJaegeuk Kim struct f2fs_inode *raw = F2FS_INODE(page); 151e7d55452SJaegeuk Kim char *name; 152441ac5cbSJaegeuk Kim 153441ac5cbSJaegeuk Kim inode->i_mode = le16_to_cpu(raw->i_mode); 154441ac5cbSJaegeuk Kim i_size_write(inode, le64_to_cpu(raw->i_size)); 155441ac5cbSJaegeuk Kim inode->i_atime.tv_sec = le64_to_cpu(raw->i_mtime); 156441ac5cbSJaegeuk Kim inode->i_ctime.tv_sec = le64_to_cpu(raw->i_ctime); 157441ac5cbSJaegeuk Kim inode->i_mtime.tv_sec = le64_to_cpu(raw->i_mtime); 158441ac5cbSJaegeuk Kim inode->i_atime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); 159441ac5cbSJaegeuk Kim inode->i_ctime.tv_nsec = le32_to_cpu(raw->i_ctime_nsec); 160441ac5cbSJaegeuk Kim inode->i_mtime.tv_nsec = le32_to_cpu(raw->i_mtime_nsec); 161f356fe0cSJaegeuk Kim 162e7d55452SJaegeuk Kim if (file_enc_name(inode)) 163e7d55452SJaegeuk Kim name = "<encrypted>"; 164e7d55452SJaegeuk Kim else 165e7d55452SJaegeuk Kim name = F2FS_INODE(page)->i_name; 166e7d55452SJaegeuk Kim 167f356fe0cSJaegeuk Kim f2fs_msg(inode->i_sb, KERN_NOTICE, "recover_inode: ino = %x, name = %s", 168e7d55452SJaegeuk Kim ino_of_node(page), name); 169d624c96fSJaegeuk Kim } 170d624c96fSJaegeuk Kim 171d624c96fSJaegeuk Kim static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) 172d624c96fSJaegeuk Kim { 173d71b5564SJaegeuk Kim unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 174d624c96fSJaegeuk Kim struct curseg_info *curseg; 1754c521f49SJaegeuk Kim struct page *page = NULL; 176d624c96fSJaegeuk Kim block_t blkaddr; 177d624c96fSJaegeuk Kim int err = 0; 178d624c96fSJaegeuk Kim 179d624c96fSJaegeuk Kim /* get node pages in the current segment */ 180d624c96fSJaegeuk Kim curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); 181695fd1edSChao Yu blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 182d624c96fSJaegeuk Kim 183635aee1fSChao Yu ra_meta_pages(sbi, blkaddr, 1, META_POR); 184635aee1fSChao Yu 185d624c96fSJaegeuk Kim while (1) { 186d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 187d624c96fSJaegeuk Kim 188f0c9cadaSChao Yu if (!is_valid_blkaddr(sbi, blkaddr, META_POR)) 1894c521f49SJaegeuk Kim return 0; 190d624c96fSJaegeuk Kim 191635aee1fSChao Yu page = get_meta_page(sbi, blkaddr); 192393ff91fSJaegeuk Kim 1936ead1142SJaegeuk Kim if (cp_ver != cpver_of_node(page)) 194f356fe0cSJaegeuk Kim break; 195d624c96fSJaegeuk Kim 196d624c96fSJaegeuk Kim if (!is_fsync_dnode(page)) 197d624c96fSJaegeuk Kim goto next; 198d624c96fSJaegeuk Kim 199d624c96fSJaegeuk Kim entry = get_fsync_inode(head, ino_of_node(page)); 200418f6c27SJaegeuk Kim if (!entry) { 201d624c96fSJaegeuk Kim if (IS_INODE(page) && is_dent_dnode(page)) { 2026ead1142SJaegeuk Kim err = recover_inode_page(sbi, page); 2036ead1142SJaegeuk Kim if (err) 204f356fe0cSJaegeuk Kim break; 205d624c96fSJaegeuk Kim } 206d624c96fSJaegeuk Kim 207d624c96fSJaegeuk Kim /* add this fsync inode to the list */ 208c52e1b10SJaegeuk Kim entry = kmem_cache_alloc(fsync_entry_slab, GFP_F2FS_ZERO); 209d624c96fSJaegeuk Kim if (!entry) { 210d624c96fSJaegeuk Kim err = -ENOMEM; 211f356fe0cSJaegeuk Kim break; 212d624c96fSJaegeuk Kim } 213441ac5cbSJaegeuk Kim /* 214441ac5cbSJaegeuk Kim * CP | dnode(F) | inode(DF) 215441ac5cbSJaegeuk Kim * For this case, we should not give up now. 216441ac5cbSJaegeuk Kim */ 217d624c96fSJaegeuk Kim entry->inode = f2fs_iget(sbi->sb, ino_of_node(page)); 218d624c96fSJaegeuk Kim if (IS_ERR(entry->inode)) { 219d624c96fSJaegeuk Kim err = PTR_ERR(entry->inode); 220fd8bb65fSNamjae Jeon kmem_cache_free(fsync_entry_slab, entry); 2218fbc418fSJaegeuk Kim if (err == -ENOENT) { 2228fbc418fSJaegeuk Kim err = 0; 223441ac5cbSJaegeuk Kim goto next; 2248fbc418fSJaegeuk Kim } 225f356fe0cSJaegeuk Kim break; 226d624c96fSJaegeuk Kim } 227fd8bb65fSNamjae Jeon list_add_tail(&entry->list, head); 228d624c96fSJaegeuk Kim } 229addbe45bSJaegeuk Kim entry->blkaddr = blkaddr; 230addbe45bSJaegeuk Kim 231c52e1b10SJaegeuk Kim if (IS_INODE(page)) { 232c52e1b10SJaegeuk Kim entry->last_inode = blkaddr; 233c52e1b10SJaegeuk Kim if (is_dent_dnode(page)) 234c52e1b10SJaegeuk Kim entry->last_dentry = blkaddr; 235c52e1b10SJaegeuk Kim } 236d624c96fSJaegeuk Kim next: 237d624c96fSJaegeuk Kim /* check next segment */ 238d624c96fSJaegeuk Kim blkaddr = next_blkaddr_of_node(page); 2394c521f49SJaegeuk Kim f2fs_put_page(page, 1); 240635aee1fSChao Yu 241635aee1fSChao Yu ra_meta_pages_cond(sbi, blkaddr); 242d624c96fSJaegeuk Kim } 2434c521f49SJaegeuk Kim f2fs_put_page(page, 1); 244d624c96fSJaegeuk Kim return err; 245d624c96fSJaegeuk Kim } 246d624c96fSJaegeuk Kim 2475ebefc5bSGu Zheng static void destroy_fsync_dnodes(struct list_head *head) 248d624c96fSJaegeuk Kim { 249d8b79b2fSDan Carpenter struct fsync_inode_entry *entry, *tmp; 250d8b79b2fSDan Carpenter 251d8b79b2fSDan Carpenter list_for_each_entry_safe(entry, tmp, head, list) { 252d624c96fSJaegeuk Kim iput(entry->inode); 253d624c96fSJaegeuk Kim list_del(&entry->list); 254d624c96fSJaegeuk Kim kmem_cache_free(fsync_entry_slab, entry); 255d624c96fSJaegeuk Kim } 256d624c96fSJaegeuk Kim } 257d624c96fSJaegeuk Kim 25839cf72cfSJaegeuk Kim static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, 259b292dcabSJaegeuk Kim block_t blkaddr, struct dnode_of_data *dn) 260d624c96fSJaegeuk Kim { 261d624c96fSJaegeuk Kim struct seg_entry *sentry; 262d624c96fSJaegeuk Kim unsigned int segno = GET_SEGNO(sbi, blkaddr); 263491c0854SJaegeuk Kim unsigned short blkoff = GET_BLKOFF_FROM_SEG0(sbi, blkaddr); 264f6517cfcSJaegeuk Kim struct f2fs_summary_block *sum_node; 265d624c96fSJaegeuk Kim struct f2fs_summary sum; 266f6517cfcSJaegeuk Kim struct page *sum_page, *node_page; 267c9ef4810SJaegeuk Kim struct dnode_of_data tdn = *dn; 268b292dcabSJaegeuk Kim nid_t ino, nid; 269d624c96fSJaegeuk Kim struct inode *inode; 270de93653fSJaegeuk Kim unsigned int offset; 271d624c96fSJaegeuk Kim block_t bidx; 272d624c96fSJaegeuk Kim int i; 273d624c96fSJaegeuk Kim 274d624c96fSJaegeuk Kim sentry = get_seg_entry(sbi, segno); 275d624c96fSJaegeuk Kim if (!f2fs_test_bit(blkoff, sentry->cur_valid_map)) 27639cf72cfSJaegeuk Kim return 0; 277d624c96fSJaegeuk Kim 278d624c96fSJaegeuk Kim /* Get the previous summary */ 279d624c96fSJaegeuk Kim for (i = CURSEG_WARM_DATA; i <= CURSEG_COLD_DATA; i++) { 280d624c96fSJaegeuk Kim struct curseg_info *curseg = CURSEG_I(sbi, i); 281d624c96fSJaegeuk Kim if (curseg->segno == segno) { 282d624c96fSJaegeuk Kim sum = curseg->sum_blk->entries[blkoff]; 283f6517cfcSJaegeuk Kim goto got_it; 284d624c96fSJaegeuk Kim } 285d624c96fSJaegeuk Kim } 286d624c96fSJaegeuk Kim 287f6517cfcSJaegeuk Kim sum_page = get_sum_page(sbi, segno); 288f6517cfcSJaegeuk Kim sum_node = (struct f2fs_summary_block *)page_address(sum_page); 289f6517cfcSJaegeuk Kim sum = sum_node->entries[blkoff]; 290f6517cfcSJaegeuk Kim f2fs_put_page(sum_page, 1); 291f6517cfcSJaegeuk Kim got_it: 292b292dcabSJaegeuk Kim /* Use the locked dnode page and inode */ 293b292dcabSJaegeuk Kim nid = le32_to_cpu(sum.nid); 294b292dcabSJaegeuk Kim if (dn->inode->i_ino == nid) { 295b292dcabSJaegeuk Kim tdn.nid = nid; 296c9ef4810SJaegeuk Kim if (!dn->inode_page_locked) 297c9ef4810SJaegeuk Kim lock_page(dn->inode_page); 298b292dcabSJaegeuk Kim tdn.node_page = dn->inode_page; 299060dd67bSJaegeuk Kim tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 300c9ef4810SJaegeuk Kim goto truncate_out; 301b292dcabSJaegeuk Kim } else if (dn->nid == nid) { 302060dd67bSJaegeuk Kim tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 303c9ef4810SJaegeuk Kim goto truncate_out; 304b292dcabSJaegeuk Kim } 305b292dcabSJaegeuk Kim 306d624c96fSJaegeuk Kim /* Get the node page */ 307b292dcabSJaegeuk Kim node_page = get_node_page(sbi, nid); 30839cf72cfSJaegeuk Kim if (IS_ERR(node_page)) 30939cf72cfSJaegeuk Kim return PTR_ERR(node_page); 310de93653fSJaegeuk Kim 311de93653fSJaegeuk Kim offset = ofs_of_node(node_page); 312d624c96fSJaegeuk Kim ino = ino_of_node(node_page); 313d624c96fSJaegeuk Kim f2fs_put_page(node_page, 1); 314d624c96fSJaegeuk Kim 31560979115SJaegeuk Kim if (ino != dn->inode->i_ino) { 316d624c96fSJaegeuk Kim /* Deallocate previous index in the node page */ 317d4686d56SJaegeuk Kim inode = f2fs_iget(sbi->sb, ino); 31806025f4dSNamjae Jeon if (IS_ERR(inode)) 31939cf72cfSJaegeuk Kim return PTR_ERR(inode); 32060979115SJaegeuk Kim } else { 32160979115SJaegeuk Kim inode = dn->inode; 32260979115SJaegeuk Kim } 32306025f4dSNamjae Jeon 324de93653fSJaegeuk Kim bidx = start_bidx_of_node(offset, F2FS_I(inode)) + 325de93653fSJaegeuk Kim le16_to_cpu(sum.ofs_in_node); 326de93653fSJaegeuk Kim 327c9ef4810SJaegeuk Kim /* 328c9ef4810SJaegeuk Kim * if inode page is locked, unlock temporarily, but its reference 329c9ef4810SJaegeuk Kim * count keeps alive. 330c9ef4810SJaegeuk Kim */ 331c9ef4810SJaegeuk Kim if (ino == dn->inode->i_ino && dn->inode_page_locked) 332c9ef4810SJaegeuk Kim unlock_page(dn->inode_page); 333c9ef4810SJaegeuk Kim 334c9ef4810SJaegeuk Kim set_new_dnode(&tdn, inode, NULL, NULL, 0); 33560979115SJaegeuk Kim if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE)) 336c9ef4810SJaegeuk Kim goto out; 337c9ef4810SJaegeuk Kim 338c9ef4810SJaegeuk Kim if (tdn.data_blkaddr == blkaddr) 33960979115SJaegeuk Kim truncate_data_blocks_range(&tdn, 1); 340c9ef4810SJaegeuk Kim 341c9ef4810SJaegeuk Kim f2fs_put_dnode(&tdn); 342c9ef4810SJaegeuk Kim out: 343c9ef4810SJaegeuk Kim if (ino != dn->inode->i_ino) 344c9ef4810SJaegeuk Kim iput(inode); 345c9ef4810SJaegeuk Kim else if (dn->inode_page_locked) 346c9ef4810SJaegeuk Kim lock_page(dn->inode_page); 347c9ef4810SJaegeuk Kim return 0; 348c9ef4810SJaegeuk Kim 349c9ef4810SJaegeuk Kim truncate_out: 350c9ef4810SJaegeuk Kim if (datablock_addr(tdn.node_page, tdn.ofs_in_node) == blkaddr) 351c9ef4810SJaegeuk Kim truncate_data_blocks_range(&tdn, 1); 352c9ef4810SJaegeuk Kim if (dn->inode->i_ino == nid && !dn->inode_page_locked) 353c9ef4810SJaegeuk Kim unlock_page(dn->inode_page); 35439cf72cfSJaegeuk Kim return 0; 355d624c96fSJaegeuk Kim } 356d624c96fSJaegeuk Kim 3576ead1142SJaegeuk Kim static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, 358d624c96fSJaegeuk Kim struct page *page, block_t blkaddr) 359d624c96fSJaegeuk Kim { 360de93653fSJaegeuk Kim struct f2fs_inode_info *fi = F2FS_I(inode); 361d624c96fSJaegeuk Kim unsigned int start, end; 362d624c96fSJaegeuk Kim struct dnode_of_data dn; 363d624c96fSJaegeuk Kim struct node_info ni; 364f356fe0cSJaegeuk Kim int err = 0, recovered = 0; 365d624c96fSJaegeuk Kim 3661c35a90eSJaegeuk Kim /* step 1: recover xattr */ 3671c35a90eSJaegeuk Kim if (IS_INODE(page)) { 36870cfed88SChao Yu recover_inline_xattr(inode, page); 3691c35a90eSJaegeuk Kim } else if (f2fs_has_xattr_block(ofs_of_node(page))) { 370bc4a1f87SJaegeuk Kim /* 371bc4a1f87SJaegeuk Kim * Deprecated; xattr blocks should be found from cold log. 372bc4a1f87SJaegeuk Kim * But, we should remain this for backward compatibility. 373bc4a1f87SJaegeuk Kim */ 3741c35a90eSJaegeuk Kim recover_xattr_data(inode, page, blkaddr); 3751c35a90eSJaegeuk Kim goto out; 3761c35a90eSJaegeuk Kim } 37770cfed88SChao Yu 3781c35a90eSJaegeuk Kim /* step 2: recover inline data */ 3791e1bb4baSJaegeuk Kim if (recover_inline_data(inode, page)) 3801e1bb4baSJaegeuk Kim goto out; 3811e1bb4baSJaegeuk Kim 3821c35a90eSJaegeuk Kim /* step 3: recover data indices */ 383de93653fSJaegeuk Kim start = start_bidx_of_node(ofs_of_node(page), fi); 3846403eb1fSChao Yu end = start + ADDRS_PER_PAGE(page, fi); 385d624c96fSJaegeuk Kim 386e479556bSGu Zheng f2fs_lock_op(sbi); 3871e1bb4baSJaegeuk Kim 388d624c96fSJaegeuk Kim set_new_dnode(&dn, inode, NULL, NULL, 0); 38939936837SJaegeuk Kim 3906ead1142SJaegeuk Kim err = get_dnode_of_data(&dn, start, ALLOC_NODE); 39139936837SJaegeuk Kim if (err) { 392e479556bSGu Zheng f2fs_unlock_op(sbi); 3931e1bb4baSJaegeuk Kim goto out; 39439936837SJaegeuk Kim } 395d624c96fSJaegeuk Kim 3963cb5ad15SJaegeuk Kim f2fs_wait_on_page_writeback(dn.node_page, NODE); 397d624c96fSJaegeuk Kim 398d624c96fSJaegeuk Kim get_node_info(sbi, dn.nid, &ni); 3999850cf4aSJaegeuk Kim f2fs_bug_on(sbi, ni.ino != ino_of_node(page)); 4009850cf4aSJaegeuk Kim f2fs_bug_on(sbi, ofs_of_node(dn.node_page) != ofs_of_node(page)); 401d624c96fSJaegeuk Kim 40212a8343eSChao Yu for (; start < end; start++, dn.ofs_in_node++) { 403d624c96fSJaegeuk Kim block_t src, dest; 404d624c96fSJaegeuk Kim 405d624c96fSJaegeuk Kim src = datablock_addr(dn.node_page, dn.ofs_in_node); 406d624c96fSJaegeuk Kim dest = datablock_addr(page, dn.ofs_in_node); 407d624c96fSJaegeuk Kim 40812a8343eSChao Yu /* skip recovering if dest is the same as src */ 40912a8343eSChao Yu if (src == dest) 41012a8343eSChao Yu continue; 41112a8343eSChao Yu 41212a8343eSChao Yu /* dest is invalid, just invalidate src block */ 41312a8343eSChao Yu if (dest == NULL_ADDR) { 41412a8343eSChao Yu truncate_data_blocks_range(&dn, 1); 41512a8343eSChao Yu continue; 41612a8343eSChao Yu } 41712a8343eSChao Yu 41812a8343eSChao Yu /* 41912a8343eSChao Yu * dest is reserved block, invalidate src block 42012a8343eSChao Yu * and then reserve one new block in dnode page. 42112a8343eSChao Yu */ 42212a8343eSChao Yu if (dest == NEW_ADDR) { 42312a8343eSChao Yu truncate_data_blocks_range(&dn, 1); 42412a8343eSChao Yu err = reserve_new_block(&dn); 42512a8343eSChao Yu f2fs_bug_on(sbi, err); 42612a8343eSChao Yu continue; 42712a8343eSChao Yu } 42812a8343eSChao Yu 42912a8343eSChao Yu /* dest is valid block, try to recover from src to dest */ 43012a8343eSChao Yu if (is_valid_blkaddr(sbi, dest, META_POR)) { 431e03b07d9SJaegeuk Kim 432d624c96fSJaegeuk Kim if (src == NULL_ADDR) { 4335d56b671SJaegeuk Kim err = reserve_new_block(&dn); 434d624c96fSJaegeuk Kim /* We should not get -ENOSPC */ 4359850cf4aSJaegeuk Kim f2fs_bug_on(sbi, err); 436d624c96fSJaegeuk Kim } 437d624c96fSJaegeuk Kim 438d624c96fSJaegeuk Kim /* Check the previous node page having this index */ 43939cf72cfSJaegeuk Kim err = check_index_in_prev_nodes(sbi, dest, &dn); 44039cf72cfSJaegeuk Kim if (err) 44139cf72cfSJaegeuk Kim goto err; 442d624c96fSJaegeuk Kim 443d624c96fSJaegeuk Kim /* write dummy data page */ 444528e3459SChao Yu f2fs_replace_block(sbi, &dn, src, dest, 445528e3459SChao Yu ni.version, false); 446f356fe0cSJaegeuk Kim recovered++; 447d624c96fSJaegeuk Kim } 448d624c96fSJaegeuk Kim } 449d624c96fSJaegeuk Kim 450d624c96fSJaegeuk Kim if (IS_INODE(dn.node_page)) 451d624c96fSJaegeuk Kim sync_inode_page(&dn); 452d624c96fSJaegeuk Kim 453d624c96fSJaegeuk Kim copy_node_footer(dn.node_page, page); 454d624c96fSJaegeuk Kim fill_node_footer(dn.node_page, dn.nid, ni.ino, 455d624c96fSJaegeuk Kim ofs_of_node(page), false); 456d624c96fSJaegeuk Kim set_page_dirty(dn.node_page); 45739cf72cfSJaegeuk Kim err: 458d624c96fSJaegeuk Kim f2fs_put_dnode(&dn); 459e479556bSGu Zheng f2fs_unlock_op(sbi); 4601e1bb4baSJaegeuk Kim out: 4616c311ec6SChris Fries f2fs_msg(sbi->sb, KERN_NOTICE, 4626c311ec6SChris Fries "recover_data: ino = %lx, recovered = %d blocks, err = %d", 46339cf72cfSJaegeuk Kim inode->i_ino, recovered, err); 46439cf72cfSJaegeuk Kim return err; 465d624c96fSJaegeuk Kim } 466d624c96fSJaegeuk Kim 4676ead1142SJaegeuk Kim static int recover_data(struct f2fs_sb_info *sbi, 468d624c96fSJaegeuk Kim struct list_head *head, int type) 469d624c96fSJaegeuk Kim { 470d71b5564SJaegeuk Kim unsigned long long cp_ver = cur_cp_version(F2FS_CKPT(sbi)); 471d624c96fSJaegeuk Kim struct curseg_info *curseg; 4724c521f49SJaegeuk Kim struct page *page = NULL; 4736ead1142SJaegeuk Kim int err = 0; 474d624c96fSJaegeuk Kim block_t blkaddr; 475d624c96fSJaegeuk Kim 476d624c96fSJaegeuk Kim /* get node pages in the current segment */ 477d624c96fSJaegeuk Kim curseg = CURSEG_I(sbi, type); 478d624c96fSJaegeuk Kim blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 479d624c96fSJaegeuk Kim 480d624c96fSJaegeuk Kim while (1) { 481d624c96fSJaegeuk Kim struct fsync_inode_entry *entry; 482d624c96fSJaegeuk Kim 483f0c9cadaSChao Yu if (!is_valid_blkaddr(sbi, blkaddr, META_POR)) 48445856affSJaegeuk Kim break; 485d624c96fSJaegeuk Kim 486635aee1fSChao Yu ra_meta_pages_cond(sbi, blkaddr); 487635aee1fSChao Yu 488635aee1fSChao Yu page = get_meta_page(sbi, blkaddr); 4894c521f49SJaegeuk Kim 4904c521f49SJaegeuk Kim if (cp_ver != cpver_of_node(page)) { 4914c521f49SJaegeuk Kim f2fs_put_page(page, 1); 4924c521f49SJaegeuk Kim break; 4934c521f49SJaegeuk Kim } 4944c521f49SJaegeuk Kim 495d624c96fSJaegeuk Kim entry = get_fsync_inode(head, ino_of_node(page)); 496d624c96fSJaegeuk Kim if (!entry) 497d624c96fSJaegeuk Kim goto next; 498441ac5cbSJaegeuk Kim /* 499441ac5cbSJaegeuk Kim * inode(x) | CP | inode(x) | dnode(F) 500441ac5cbSJaegeuk Kim * In this case, we can lose the latest inode(x). 501c52e1b10SJaegeuk Kim * So, call recover_inode for the inode update. 502441ac5cbSJaegeuk Kim */ 503c52e1b10SJaegeuk Kim if (entry->last_inode == blkaddr) 504c52e1b10SJaegeuk Kim recover_inode(entry->inode, page); 505c52e1b10SJaegeuk Kim if (entry->last_dentry == blkaddr) { 506c52e1b10SJaegeuk Kim err = recover_dentry(entry->inode, page); 507c52e1b10SJaegeuk Kim if (err) { 508c52e1b10SJaegeuk Kim f2fs_put_page(page, 1); 509c52e1b10SJaegeuk Kim break; 510c52e1b10SJaegeuk Kim } 511c52e1b10SJaegeuk Kim } 5126ead1142SJaegeuk Kim err = do_recover_data(sbi, entry->inode, page, blkaddr); 5134c521f49SJaegeuk Kim if (err) { 5144c521f49SJaegeuk Kim f2fs_put_page(page, 1); 51545856affSJaegeuk Kim break; 5164c521f49SJaegeuk Kim } 517d624c96fSJaegeuk Kim 518d624c96fSJaegeuk Kim if (entry->blkaddr == blkaddr) { 519d624c96fSJaegeuk Kim iput(entry->inode); 520d624c96fSJaegeuk Kim list_del(&entry->list); 521d624c96fSJaegeuk Kim kmem_cache_free(fsync_entry_slab, entry); 522d624c96fSJaegeuk Kim } 523d624c96fSJaegeuk Kim next: 524d624c96fSJaegeuk Kim /* check next segment */ 525d624c96fSJaegeuk Kim blkaddr = next_blkaddr_of_node(page); 5264c521f49SJaegeuk Kim f2fs_put_page(page, 1); 527d624c96fSJaegeuk Kim } 5286ead1142SJaegeuk Kim if (!err) 529d624c96fSJaegeuk Kim allocate_new_segments(sbi); 5306ead1142SJaegeuk Kim return err; 531d624c96fSJaegeuk Kim } 532d624c96fSJaegeuk Kim 5336ead1142SJaegeuk Kim int recover_fsync_data(struct f2fs_sb_info *sbi) 534d624c96fSJaegeuk Kim { 535cf2271e7SJaegeuk Kim struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE); 536d624c96fSJaegeuk Kim struct list_head inode_list; 537cf2271e7SJaegeuk Kim block_t blkaddr; 5386ead1142SJaegeuk Kim int err; 539aabe5136SHaicheng Li bool need_writecp = false; 540d624c96fSJaegeuk Kim 541d624c96fSJaegeuk Kim fsync_entry_slab = f2fs_kmem_cache_create("f2fs_fsync_inode_entry", 542e8512d2eSGu Zheng sizeof(struct fsync_inode_entry)); 5436bacf52fSJaegeuk Kim if (!fsync_entry_slab) 5446ead1142SJaegeuk Kim return -ENOMEM; 545d624c96fSJaegeuk Kim 546d624c96fSJaegeuk Kim INIT_LIST_HEAD(&inode_list); 547d624c96fSJaegeuk Kim 548d624c96fSJaegeuk Kim /* step #1: find fsynced inode numbers */ 549caf0047eSChao Yu set_sbi_flag(sbi, SBI_POR_DOING); 550cf2271e7SJaegeuk Kim 55114f4e690SJaegeuk Kim /* prevent checkpoint */ 55214f4e690SJaegeuk Kim mutex_lock(&sbi->cp_mutex); 55314f4e690SJaegeuk Kim 554cf2271e7SJaegeuk Kim blkaddr = NEXT_FREE_BLKADDR(sbi, curseg); 555cf2271e7SJaegeuk Kim 5566ead1142SJaegeuk Kim err = find_fsync_dnodes(sbi, &inode_list); 5576ead1142SJaegeuk Kim if (err) 558d624c96fSJaegeuk Kim goto out; 559d624c96fSJaegeuk Kim 560d624c96fSJaegeuk Kim if (list_empty(&inode_list)) 561d624c96fSJaegeuk Kim goto out; 562d624c96fSJaegeuk Kim 563aabe5136SHaicheng Li need_writecp = true; 564691c6fd2SChao Yu 565d624c96fSJaegeuk Kim /* step #2: recover data */ 5666ead1142SJaegeuk Kim err = recover_data(sbi, &inode_list, CURSEG_WARM_NODE); 567b307384eSJaegeuk Kim if (!err) 5689850cf4aSJaegeuk Kim f2fs_bug_on(sbi, !list_empty(&inode_list)); 569d624c96fSJaegeuk Kim out: 5705ebefc5bSGu Zheng destroy_fsync_dnodes(&inode_list); 571d624c96fSJaegeuk Kim kmem_cache_destroy(fsync_entry_slab); 572cf2271e7SJaegeuk Kim 5734c521f49SJaegeuk Kim /* truncate meta pages to be used by the recovery */ 5744c521f49SJaegeuk Kim truncate_inode_pages_range(META_MAPPING(sbi), 5757cd8558bSJaegeuk Kim MAIN_BLKADDR(sbi) << PAGE_CACHE_SHIFT, -1); 5764c521f49SJaegeuk Kim 577cf2271e7SJaegeuk Kim if (err) { 578cf2271e7SJaegeuk Kim truncate_inode_pages_final(NODE_MAPPING(sbi)); 579cf2271e7SJaegeuk Kim truncate_inode_pages_final(META_MAPPING(sbi)); 580cf2271e7SJaegeuk Kim } 581cf2271e7SJaegeuk Kim 582caf0047eSChao Yu clear_sbi_flag(sbi, SBI_POR_DOING); 583cf2271e7SJaegeuk Kim if (err) { 584e90c2d28SChao Yu bool invalidate = false; 585e90c2d28SChao Yu 586e90c2d28SChao Yu if (discard_next_dnode(sbi, blkaddr)) 587e90c2d28SChao Yu invalidate = true; 588cf2271e7SJaegeuk Kim 589cf2271e7SJaegeuk Kim /* Flush all the NAT/SIT pages */ 590cf2271e7SJaegeuk Kim while (get_pages(sbi, F2FS_DIRTY_META)) 591cf2271e7SJaegeuk Kim sync_meta_pages(sbi, META, LONG_MAX); 592e90c2d28SChao Yu 593e90c2d28SChao Yu /* invalidate temporary meta page */ 594e90c2d28SChao Yu if (invalidate) 595e90c2d28SChao Yu invalidate_mapping_pages(META_MAPPING(sbi), 596e90c2d28SChao Yu blkaddr, blkaddr); 597e90c2d28SChao Yu 59814f4e690SJaegeuk Kim set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG); 59914f4e690SJaegeuk Kim mutex_unlock(&sbi->cp_mutex); 600cf2271e7SJaegeuk Kim } else if (need_writecp) { 60175ab4cb8SJaegeuk Kim struct cp_control cpc = { 60210027551SJaegeuk Kim .reason = CP_RECOVERY, 60375ab4cb8SJaegeuk Kim }; 60414f4e690SJaegeuk Kim mutex_unlock(&sbi->cp_mutex); 60575ab4cb8SJaegeuk Kim write_checkpoint(sbi, &cpc); 60614f4e690SJaegeuk Kim } else { 60714f4e690SJaegeuk Kim mutex_unlock(&sbi->cp_mutex); 608cf2271e7SJaegeuk Kim } 6096ead1142SJaegeuk Kim return err; 610d624c96fSJaegeuk Kim } 611