aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJaegeuk Kim <jaegeuk@kernel.org>2015-03-26 21:46:38 -0400
committerJaegeuk Kim <jaegeuk@kernel.org>2015-04-10 18:08:56 -0400
commitc9ef481097d17fb8ff8ea7930ce715b5a676f10f (patch)
tree36dc00bc17bb7ec2ac6f7993d173c95f90c5bc31
parentadad81ed42bbc537f37192dcdd9a83e34bb61987 (diff)
f2fs: fix mismatching lock and unlock pages for roll-forward recovery
Previously, inode page is not correctly locked and unlocked in pair during the roll-forward recovery. Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
-rw-r--r--fs/f2fs/recovery.c48
1 files changed, 31 insertions, 17 deletions
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index e60ffaa380f1..c69de88a6453 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -258,6 +258,7 @@ static int check_index_in_prev_nodes(struct f2fs_sb_info *sbi,
258 struct f2fs_summary_block *sum_node; 258 struct f2fs_summary_block *sum_node;
259 struct f2fs_summary sum; 259 struct f2fs_summary sum;
260 struct page *sum_page, *node_page; 260 struct page *sum_page, *node_page;
261 struct dnode_of_data tdn = *dn;
261 nid_t ino, nid; 262 nid_t ino, nid;
262 struct inode *inode; 263 struct inode *inode;
263 unsigned int offset; 264 unsigned int offset;
@@ -285,17 +286,15 @@ got_it:
285 /* Use the locked dnode page and inode */ 286 /* Use the locked dnode page and inode */
286 nid = le32_to_cpu(sum.nid); 287 nid = le32_to_cpu(sum.nid);
287 if (dn->inode->i_ino == nid) { 288 if (dn->inode->i_ino == nid) {
288 struct dnode_of_data tdn = *dn;
289 tdn.nid = nid; 289 tdn.nid = nid;
290 if (!dn->inode_page_locked)
291 lock_page(dn->inode_page);
290 tdn.node_page = dn->inode_page; 292 tdn.node_page = dn->inode_page;
291 tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 293 tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node);
292 truncate_data_blocks_range(&tdn, 1); 294 goto truncate_out;
293 return 0;
294 } else if (dn->nid == nid) { 295 } else if (dn->nid == nid) {
295 struct dnode_of_data tdn = *dn;
296 tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node); 296 tdn.ofs_in_node = le16_to_cpu(sum.ofs_in_node);
297 truncate_data_blocks_range(&tdn, 1); 297 goto truncate_out;
298 return 0;
299 } 298 }
300 299
301 /* Get the node page */ 300 /* Get the node page */
@@ -319,18 +318,33 @@ got_it:
319 bidx = start_bidx_of_node(offset, F2FS_I(inode)) + 318 bidx = start_bidx_of_node(offset, F2FS_I(inode)) +
320 le16_to_cpu(sum.ofs_in_node); 319 le16_to_cpu(sum.ofs_in_node);
321 320
322 if (ino != dn->inode->i_ino) { 321 /*
323 truncate_hole(inode, bidx, bidx + 1); 322 * if inode page is locked, unlock temporarily, but its reference
323 * count keeps alive.
324 */
325 if (ino == dn->inode->i_ino && dn->inode_page_locked)
326 unlock_page(dn->inode_page);
327
328 set_new_dnode(&tdn, inode, NULL, NULL, 0);
329 if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE))
330 goto out;
331
332 if (tdn.data_blkaddr == blkaddr)
333 truncate_data_blocks_range(&tdn, 1);
334
335 f2fs_put_dnode(&tdn);
336out:
337 if (ino != dn->inode->i_ino)
324 iput(inode); 338 iput(inode);
325 } else { 339 else if (dn->inode_page_locked)
326 struct dnode_of_data tdn; 340 lock_page(dn->inode_page);
327 set_new_dnode(&tdn, inode, dn->inode_page, NULL, 0); 341 return 0;
328 if (get_dnode_of_data(&tdn, bidx, LOOKUP_NODE)) 342
329 return 0; 343truncate_out:
330 if (tdn.data_blkaddr != NULL_ADDR) 344 if (datablock_addr(tdn.node_page, tdn.ofs_in_node) == blkaddr)
331 truncate_data_blocks_range(&tdn, 1); 345 truncate_data_blocks_range(&tdn, 1);
332 f2fs_put_page(tdn.node_page, 1); 346 if (dn->inode->i_ino == nid && !dn->inode_page_locked)
333 } 347 unlock_page(dn->inode_page);
334 return 0; 348 return 0;
335} 349}
336 350