X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fext4_extent.c;h=28db8533b4d14ce5331985143af71f4cd449dde4;hb=13875d2d90245070874fb7e85d9dcd86699bca5e;hp=f5148a7a66dad82636286cb68ccac7cb7a6bf5e3;hpb=6c6fb14455806704ea7814a31747ec551cb39928;p=lwext4.git diff --git a/src/ext4_extent.c b/src/ext4_extent.c index f5148a7..28db853 100644 --- a/src/ext4_extent.c +++ b/src/ext4_extent.c @@ -529,14 +529,14 @@ static int ext4_find_extent(struct ext4_inode_ref *inode_ref, ext4_lblk_t block, if (path) { ext4_ext_drop_refs(inode_ref, path, 0); if (depth > path[0].maxdepth) { - free(path); + ext4_free(path); *orig_path = path = NULL; } } if (!path) { int32_t path_depth = depth + 1; /* account possible depth increase */ - path = calloc(1, sizeof(struct ext4_extent_path) * + path = ext4_calloc(1, sizeof(struct ext4_extent_path) * (path_depth + 1)); if (!path) return ENOMEM; @@ -592,7 +592,7 @@ static int ext4_find_extent(struct ext4_inode_ref *inode_ref, ext4_lblk_t block, err: ext4_ext_drop_refs(inode_ref, path, 0); - free(path); + ext4_free(path); if (orig_path) *orig_path = NULL; return ret; @@ -1130,7 +1130,7 @@ again: i = depth - (level - 1); /* We split from leaf to the i-th node */ if (level > 0) { - npath = calloc(1, sizeof(struct ext4_extent_path) * + npath = ext4_calloc(1, sizeof(struct ext4_extent_path) * (level)); if (!npath) { ret = ENOMEM; @@ -1168,7 +1168,7 @@ out: } } if (npath) - free(npath); + ext4_free(npath); return ret; } @@ -1215,6 +1215,13 @@ static int ext4_ext_remove_idx(struct ext4_inode_ref *inode_ref, to_le32(path[i].index->first_block), leaf, 1); ext4_ext_free_blocks(inode_ref, leaf, 1, 0); + /* + * We may need to correct the paths after the first extents/indexes in + * a node being modified. + * + * We do not need to consider whether there's any extents presenting or + * not, as garbage will be cleared soon. + */ while (i > 0) { if (path[i].index != EXT_FIRST_INDEX(path[i].header)) break; @@ -1253,15 +1260,27 @@ static int ext4_ext_remove_leaf(struct ext4_inode_ref *inode_ref, new_start = start = to_le32(ex->first_block); len = ext4_ext_get_actual_len(ex); newblock = ext4_ext_pblock(ex); + /* + * The 1st case: + * The position that we start truncation is inside the range of an + * extent. Here we should calculate the new length of that extent and + * may start the removal from the next extent. + */ if (start < from) { len -= from - start; new_len = from - start; start = from; start_ex++; } else { + /* + * The second case: + * The last block to be truncated is inside the range of an + * extent. We need to calculate the new length and the new + * start of the extent. + */ if (start + len - 1 > to) { - len -= start + len - 1 - to; new_len = start + len - 1 - to; + len -= new_len; new_start = to + 1; newblock += to + 1 - start; ex2 = ex; @@ -1269,7 +1288,15 @@ static int ext4_ext_remove_leaf(struct ext4_inode_ref *inode_ref, } ext4_ext_remove_blocks(inode_ref, ex, start, start + len - 1); + /* + * Set the first block of the extent if it is presented. + */ ex->first_block = to_le32(new_start); + + /* + * If the new length of the current extent we are working on is + * zero, remove it. + */ if (!new_len) new_entries--; else { @@ -1286,12 +1313,21 @@ static int ext4_ext_remove_leaf(struct ext4_inode_ref *inode_ref, if (ex2 == NULL) ex2 = ex; + /* + * Move any remaining extents to the starting position of the node. + */ if (ex2 <= EXT_LAST_EXTENT(eh)) memmove(start_ex, ex2, (EXT_LAST_EXTENT(eh) - ex2 + 1) * sizeof(struct ext4_extent)); eh->entries_count = to_le16(new_entries); ext4_ext_dirty(inode_ref, path + depth); + + /* + * If the extent pointer is pointed to the first extent of the node, and + * there's still extents presenting, we may need to correct the indexes + * of the paths. + */ if (path[depth].extent == EXT_FIRST_EXTENT(eh) && eh->entries_count) { err = ext4_ext_correct_indexes(inode_ref, path); if (err != EOK) @@ -1308,6 +1344,9 @@ static int ext4_ext_remove_leaf(struct ext4_inode_ref *inode_ref, return err; } +/* + * Check if there's more to remove at a specific level. + */ static bool ext4_ext_more_to_rm(struct ext4_extent_path *path, ext4_lblk_t to) { if (!to_le16(path->header->entries_count)) @@ -1427,6 +1466,9 @@ int ext4_extent_remove_space(struct ext4_inode_ref *inode_ref, ext4_lblk_t from, i++; } else { if (i > 0) { + /* + * Garbage entries will finally be cleared here. + */ if (!eh->entries_count) ret = ext4_ext_remove_idx(inode_ref, path, i - 1); @@ -1456,7 +1498,7 @@ int ext4_extent_remove_space(struct ext4_inode_ref *inode_ref, ext4_lblk_t from, out: ext4_ext_drop_refs(inode_ref, path, 0); - free(path); + ext4_free(path); path = NULL; return ret; } @@ -1750,7 +1792,7 @@ out: out2: if (path) { ext4_ext_drop_refs(inode_ref, path, 0); - free(path); + ext4_free(path); } return err;