aboutsummaryrefslogtreecommitdiffstats
path: root/fs/f2fs
diff options
context:
space:
mode:
authorshifei10.ge <shifei10.ge@samsung.com>2013-10-29 03:32:34 -0400
committerJaegeuk Kim <jaegeuk.kim@samsung.com>2014-01-06 02:42:21 -0500
commita225dca39495f7c18f1210306281c9c41a3454f6 (patch)
tree838aa3ffe74b4a76ed834a7ef969a1e76be41433 /fs/f2fs
parenta8865372a8414298982e07f4ac8d6dc0ab1e0a3d (diff)
f2fs: fix truncate_partial_nodes bug
The truncate_partial_nodes puts pages incorrectly in the following two cases. Note that the value for argc 'depth' can only be 2 or 3. Please see truncate_inode_blocks() and truncate_partial_nodes(). 1) An err is occurred in the first 'for' loop When err is occurred with depth = 2, pages[0] is invalid, so this page doesn't need to be put. There is no problem, however, when depth is 3, it doesn't put the pages correctly where pages[0] is valid and pages[1] is invalid. In this case, depth is set to 2 (ref to statemnt depth = i + 1), and then 'goto fail'. In label 'fail', for (i = depth - 3; i >= 0; i--) cannot meet the condition because i = -1, so pages[0] cann't be put. 2) An err happened in the second 'for' loop Now we've got pages[0] with depth = 2, or we've got pages[0] and pages[1] with depth = 3. When an err is detected, we need 'goto fail' to put such the pages. When depth is 2, in label 'fail', for (i = depth - 3; i >= 0; i--) cann't meet the condition because i = -1, so pages[0] cann't be put. When depth is 3, in label 'fail', for (i = depth - 3; i >= 0; i--) can only put pages[0], pages[1] also cann't be put. Note that 'depth' has been changed before first 'goto fail' (ref to statemnt depth = i + 1), so passing this modified 'depth' to the tracepoint, trace_f2fs_truncate_partial_nodes, is also incorrect. Signed-off-by: Shifei Ge <shifei10.ge@samsung.com> [Jaegeuk Kim: modify the description and fix one bug] Signed-off-by: Jaegeuk Kim <jaegeuk.kim@samsung.com>
Diffstat (limited to 'fs/f2fs')
-rw-r--r--fs/f2fs/node.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 9405a17a671e..0230326be495 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -633,19 +633,19 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
633 return 0; 633 return 0;
634 634
635 /* get indirect nodes in the path */ 635 /* get indirect nodes in the path */
636 for (i = 0; i < depth - 1; i++) { 636 for (i = 0; i < idx + 1; i++) {
637 /* refernece count'll be increased */ 637 /* refernece count'll be increased */
638 pages[i] = get_node_page(sbi, nid[i]); 638 pages[i] = get_node_page(sbi, nid[i]);
639 if (IS_ERR(pages[i])) { 639 if (IS_ERR(pages[i])) {
640 depth = i + 1;
641 err = PTR_ERR(pages[i]); 640 err = PTR_ERR(pages[i]);
641 idx = i - 1;
642 goto fail; 642 goto fail;
643 } 643 }
644 nid[i + 1] = get_nid(pages[i], offset[i + 1], false); 644 nid[i + 1] = get_nid(pages[i], offset[i + 1], false);
645 } 645 }
646 646
647 /* free direct nodes linked to a partial indirect node */ 647 /* free direct nodes linked to a partial indirect node */
648 for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) { 648 for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) {
649 child_nid = get_nid(pages[idx], i, false); 649 child_nid = get_nid(pages[idx], i, false);
650 if (!child_nid) 650 if (!child_nid)
651 continue; 651 continue;
@@ -656,7 +656,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
656 set_nid(pages[idx], i, 0, false); 656 set_nid(pages[idx], i, 0, false);
657 } 657 }
658 658
659 if (offset[depth - 1] == 0) { 659 if (offset[idx + 1] == 0) {
660 dn->node_page = pages[idx]; 660 dn->node_page = pages[idx];
661 dn->nid = nid[idx]; 661 dn->nid = nid[idx];
662 truncate_node(dn); 662 truncate_node(dn);
@@ -664,9 +664,10 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
664 f2fs_put_page(pages[idx], 1); 664 f2fs_put_page(pages[idx], 1);
665 } 665 }
666 offset[idx]++; 666 offset[idx]++;
667 offset[depth - 1] = 0; 667 offset[idx + 1] = 0;
668 idx--;
668fail: 669fail:
669 for (i = depth - 3; i >= 0; i--) 670 for (i = idx; i >= 0; i--)
670 f2fs_put_page(pages[i], 1); 671 f2fs_put_page(pages[i], 1);
671 672
672 trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err); 673 trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err);