diff options
author | shifei10.ge <shifei10.ge@samsung.com> | 2013-10-29 03:32:34 -0400 |
---|---|---|
committer | Jaegeuk Kim <jaegeuk.kim@samsung.com> | 2014-01-06 02:42:21 -0500 |
commit | a225dca39495f7c18f1210306281c9c41a3454f6 (patch) | |
tree | 838aa3ffe74b4a76ed834a7ef969a1e76be41433 /fs/f2fs | |
parent | a8865372a8414298982e07f4ac8d6dc0ab1e0a3d (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.c | 13 |
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--; | ||
668 | fail: | 669 | fail: |
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); |