Commit a225dca3 authored by shifei10.ge's avatar shifei10.ge Committed by Jaegeuk Kim

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: default avatarShifei Ge <shifei10.ge@samsung.com>
[Jaegeuk Kim: modify the description and fix one bug]
Signed-off-by: default avatarJaegeuk Kim <jaegeuk.kim@samsung.com>
parent a8865372
...@@ -633,19 +633,19 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, ...@@ -633,19 +633,19 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
return 0; return 0;
/* get indirect nodes in the path */ /* get indirect nodes in the path */
for (i = 0; i < depth - 1; i++) { for (i = 0; i < idx + 1; i++) {
/* refernece count'll be increased */ /* refernece count'll be increased */
pages[i] = get_node_page(sbi, nid[i]); pages[i] = get_node_page(sbi, nid[i]);
if (IS_ERR(pages[i])) { if (IS_ERR(pages[i])) {
depth = i + 1;
err = PTR_ERR(pages[i]); err = PTR_ERR(pages[i]);
idx = i - 1;
goto fail; goto fail;
} }
nid[i + 1] = get_nid(pages[i], offset[i + 1], false); nid[i + 1] = get_nid(pages[i], offset[i + 1], false);
} }
/* free direct nodes linked to a partial indirect node */ /* free direct nodes linked to a partial indirect node */
for (i = offset[depth - 1]; i < NIDS_PER_BLOCK; i++) { for (i = offset[idx + 1]; i < NIDS_PER_BLOCK; i++) {
child_nid = get_nid(pages[idx], i, false); child_nid = get_nid(pages[idx], i, false);
if (!child_nid) if (!child_nid)
continue; continue;
...@@ -656,7 +656,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, ...@@ -656,7 +656,7 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
set_nid(pages[idx], i, 0, false); set_nid(pages[idx], i, 0, false);
} }
if (offset[depth - 1] == 0) { if (offset[idx + 1] == 0) {
dn->node_page = pages[idx]; dn->node_page = pages[idx];
dn->nid = nid[idx]; dn->nid = nid[idx];
truncate_node(dn); truncate_node(dn);
...@@ -664,9 +664,10 @@ static int truncate_partial_nodes(struct dnode_of_data *dn, ...@@ -664,9 +664,10 @@ static int truncate_partial_nodes(struct dnode_of_data *dn,
f2fs_put_page(pages[idx], 1); f2fs_put_page(pages[idx], 1);
} }
offset[idx]++; offset[idx]++;
offset[depth - 1] = 0; offset[idx + 1] = 0;
idx--;
fail: fail:
for (i = depth - 3; i >= 0; i--) for (i = idx; i >= 0; i--)
f2fs_put_page(pages[i], 1); f2fs_put_page(pages[i], 1);
trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err); trace_f2fs_truncate_partial_nodes(dn->inode, nid, depth, err);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment