diff options
Diffstat (limited to 'fs/f2fs/recovery.c')
-rw-r--r-- | fs/f2fs/recovery.c | 76 |
1 files changed, 44 insertions, 32 deletions
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c index 41afb9534bbd..8d8ea99f2156 100644 --- a/fs/f2fs/recovery.c +++ b/fs/f2fs/recovery.c | |||
@@ -93,10 +93,9 @@ static int recover_dentry(struct inode *inode, struct page *ipage) | |||
93 | } | 93 | } |
94 | retry: | 94 | retry: |
95 | de = f2fs_find_entry(dir, &name, &page); | 95 | de = f2fs_find_entry(dir, &name, &page); |
96 | if (de && inode->i_ino == le32_to_cpu(de->ino)) { | 96 | if (de && inode->i_ino == le32_to_cpu(de->ino)) |
97 | clear_inode_flag(F2FS_I(inode), FI_INC_LINK); | ||
98 | goto out_unmap_put; | 97 | goto out_unmap_put; |
99 | } | 98 | |
100 | if (de) { | 99 | if (de) { |
101 | einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); | 100 | einode = f2fs_iget(inode->i_sb, le32_to_cpu(de->ino)); |
102 | if (IS_ERR(einode)) { | 101 | if (IS_ERR(einode)) { |
@@ -115,7 +114,7 @@ retry: | |||
115 | iput(einode); | 114 | iput(einode); |
116 | goto retry; | 115 | goto retry; |
117 | } | 116 | } |
118 | err = __f2fs_add_link(dir, &name, inode); | 117 | err = __f2fs_add_link(dir, &name, inode, inode->i_ino, inode->i_mode); |
119 | if (err) | 118 | if (err) |
120 | goto out_err; | 119 | goto out_err; |
121 | 120 | ||
@@ -187,11 +186,7 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) | |||
187 | goto next; | 186 | goto next; |
188 | 187 | ||
189 | entry = get_fsync_inode(head, ino_of_node(page)); | 188 | entry = get_fsync_inode(head, ino_of_node(page)); |
190 | if (entry) { | 189 | if (!entry) { |
191 | if (IS_INODE(page) && is_dent_dnode(page)) | ||
192 | set_inode_flag(F2FS_I(entry->inode), | ||
193 | FI_INC_LINK); | ||
194 | } else { | ||
195 | if (IS_INODE(page) && is_dent_dnode(page)) { | 190 | if (IS_INODE(page) && is_dent_dnode(page)) { |
196 | err = recover_inode_page(sbi, page); | 191 | err = recover_inode_page(sbi, page); |
197 | if (err) | 192 | if (err) |
@@ -212,8 +207,10 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head) | |||
212 | if (IS_ERR(entry->inode)) { | 207 | if (IS_ERR(entry->inode)) { |
213 | err = PTR_ERR(entry->inode); | 208 | err = PTR_ERR(entry->inode); |
214 | kmem_cache_free(fsync_entry_slab, entry); | 209 | kmem_cache_free(fsync_entry_slab, entry); |
215 | if (err == -ENOENT) | 210 | if (err == -ENOENT) { |
211 | err = 0; | ||
216 | goto next; | 212 | goto next; |
213 | } | ||
217 | break; | 214 | break; |
218 | } | 215 | } |
219 | list_add_tail(&entry->list, head); | 216 | list_add_tail(&entry->list, head); |
@@ -256,6 +253,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi, | |||
256 | struct f2fs_summary_block *sum_node; | 253 | struct f2fs_summary_block *sum_node; |
257 | struct f2fs_summary sum; | 254 | struct f2fs_summary sum; |
258 | struct page *sum_page, *node_page; | 255 | struct page *sum_page, *node_page; |
256 | struct dnode_of_data tdn = *dn; | ||
259 | nid_t ino, nid; | 257 | nid_t ino, nid; |
260 | struct inode *inode; | 258 | struct inode *inode; |
261 | unsigned int offset; | 259 | unsigned int offset; |
@@ -283,17 +281,15 @@ got_it: | |||
283 | /* Use the locked dnode page and inode */ | 281 | /* Use the locked dnode page and inode */ |
284 | nid = le32_to_cpu(sum.nid); | 282 | nid = le32_to_cpu(sum.nid); |
285 | if (dn->inode->i_ino == nid) { | 283 | if (dn->inode->i_ino == nid) { |
286 | struct dnode_of_data tdn = *dn; | ||
287 | tdn.nid = nid; | 284 | tdn.nid = nid; |
285 | if (!dn->inode_page_locked) | ||
286 | lock_page(dn->inode_page); | ||
288 | tdn.node_page = dn->inode_page; | 287 | tdn.node_page = dn->inode_page; |
289 | tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); | 288 | tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); |
290 | truncate_data_blocks_range(&tdn, 1); | 289 | goto truncate_out; |
291 | return 0; | ||
292 | } else if (dn->nid == nid) { | 290 | } else if (dn->nid == nid) { |
293 | struct dnode_of_data tdn = *dn; | ||
294 | tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); | 291 | tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); |
295 | truncate_data_blocks_range(&tdn, 1); | 292 | goto truncate_out; |
296 | return 0; | ||
297 | } | 293 | } |
298 | 294 | ||
299 | /* Get the node page */ | 295 | /* Get the node page */ |
@@ -317,18 +313,33 @@ got_it: | |||
317 | bidx = start_bidx_of_node(offset, F2FS_I(inode)) + | 313 | bidx = start_bidx_of_node(offset, F2FS_I(inode)) + |
318 | le16_to_cpu(sum.ofs_in_node); | 314 | le16_to_cpu(sum.ofs_in_node); |
319 | 315 | ||
320 | if (ino != dn->inode->i_ino) { | 316 | /* |
321 | truncate_hole(inode, bidx, bidx + 1); | 317 | * if inode page is locked, unlock temporarily, but its reference |
318 | * count keeps alive. | ||
319 | */ | ||
320 | if (ino == dn->inode->i_ino && dn->inode_page_locked) | ||
321 | unlock_page(dn->inode_page); | ||
322 | |||
323 | set_new_dnode(&tdn, inode, NULL, NULL, 0); | ||
324 | if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE)) | ||
325 | goto out; | ||
326 | |||
327 | if (tdn.data_blkaddr == blkaddr) | ||
328 | truncate_data_blocks_range(&tdn, 1); | ||
329 | |||
330 | f2fs_put_dnode(&tdn); | ||
331 | out: | ||
332 | if (ino != dn->inode->i_ino) | ||
322 | iput(inode); | 333 | iput(inode); |
323 | } else { | 334 | else if (dn->inode_page_locked) |
324 | struct dnode_of_data tdn; | 335 | lock_page(dn->inode_page); |
325 | set_new_dnode(&tdn, inode, dn->inode_page, NULL, 0); | 336 | return 0; |
326 | if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE)) | 337 | |
327 | return 0; | 338 | truncate_out: |
328 | if (tdn.data_blkaddr != NULL_ADDR) | 339 | if (datablock_addr(tdn.node_page, tdn.ofs_in_node) == blkaddr) |
329 | truncate_data_blocks_range(&tdn, 1); | 340 | truncate_data_blocks_range(&tdn, 1); |
330 | f2fs_put_page(tdn.node_page, 1); | 341 | if (dn->inode->i_ino == nid && !dn->inode_page_locked) |
331 | } | 342 | unlock_page(dn->inode_page); |
332 | return 0; | 343 | return 0; |
333 | } | 344 | } |
334 | 345 | ||
@@ -384,7 +395,9 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
384 | src = datablock_addr(dn.node_page, dn.ofs_in_node); | 395 | src = datablock_addr(dn.node_page, dn.ofs_in_node); |
385 | dest = datablock_addr(page, dn.ofs_in_node); | 396 | dest = datablock_addr(page, dn.ofs_in_node); |
386 | 397 | ||
387 | if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR) { | 398 | if (src != dest && dest != NEW_ADDR && dest != NULL_ADDR && |
399 | dest >= MAIN_BLKADDR(sbi) && dest < MAX_BLKADDR(sbi)) { | ||
400 | |||
388 | if (src == NULL_ADDR) { | 401 | if (src == NULL_ADDR) { |
389 | err = reserve_new_block(&dn); | 402 | err = reserve_new_block(&dn); |
390 | /* We should not get -ENOSPC */ | 403 | /* We should not get -ENOSPC */ |
@@ -401,14 +414,13 @@ static int do_recover_data(struct f2fs_sb_info *sbi, struct inode *inode, | |||
401 | /* write dummy data page */ | 414 | /* write dummy data page */ |
402 | recover_data_page(sbi, NULL, &sum, src, dest); | 415 | recover_data_page(sbi, NULL, &sum, src, dest); |
403 | dn.data_blkaddr = dest; | 416 | dn.data_blkaddr = dest; |
404 | update_extent_cache(&dn); | 417 | set_data_blkaddr(&dn); |
418 | f2fs_update_extent_cache(&dn); | ||
405 | recovered++; | 419 | recovered++; |
406 | } | 420 | } |
407 | dn.ofs_in_node++; | 421 | dn.ofs_in_node++; |
408 | } | 422 | } |
409 | 423 | ||
410 | /* write node page in place */ | ||
411 | set_summary(&sum, dn.nid, 0, 0); | ||
412 | if (IS_INODE(dn.node_page)) | 424 | if (IS_INODE(dn.node_page)) |
413 | sync_inode_page(&dn); | 425 | sync_inode_page(&dn); |
414 | 426 | ||
@@ -552,7 +564,7 @@ out: | |||
552 | mutex_unlock(&sbi->cp_mutex); | 564 | mutex_unlock(&sbi->cp_mutex); |
553 | } else if (need_writecp) { | 565 | } else if (need_writecp) { |
554 | struct cp_control cpc = { | 566 | struct cp_control cpc = { |
555 | .reason = CP_SYNC, | 567 | .reason = CP_RECOVERY, |
556 | }; | 568 | }; |
557 | mutex_unlock(&sbi->cp_mutex); | 569 | mutex_unlock(&sbi->cp_mutex); |
558 | write_checkpoint(sbi, &cpc); | 570 | write_checkpoint(sbi, &cpc); |