|
@@ -2299,59 +2299,69 @@ static int ext4_fill_fiemap_extents(struct inode *inode,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * ext4_ext_put_gap_in_cache:
|
|
|
- * calculate boundaries of the gap that the requested block fits into
|
|
|
- * and cache this gap
|
|
|
+ * ext4_ext_determine_hole - determine hole around given block
|
|
|
+ * @inode: inode we lookup in
|
|
|
+ * @path: path in extent tree to @lblk
|
|
|
+ * @lblk: pointer to logical block around which we want to determine hole
|
|
|
+ *
|
|
|
+ * Determine hole length (and start if easily possible) around given logical
|
|
|
+ * block. We don't try too hard to find the beginning of the hole but @path
|
|
|
+ * actually points to extent before @lblk, we provide it.
|
|
|
+ *
|
|
|
+ * The function returns the length of a hole starting at @lblk. We update @lblk
|
|
|
+ * to the beginning of the hole if we managed to find it.
|
|
|
*/
|
|
|
-static void
|
|
|
-ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
|
|
|
- ext4_lblk_t block)
|
|
|
+static ext4_lblk_t ext4_ext_determine_hole(struct inode *inode,
|
|
|
+ struct ext4_ext_path *path,
|
|
|
+ ext4_lblk_t *lblk)
|
|
|
{
|
|
|
int depth = ext_depth(inode);
|
|
|
- ext4_lblk_t len;
|
|
|
- ext4_lblk_t lblock;
|
|
|
struct ext4_extent *ex;
|
|
|
- struct extent_status es;
|
|
|
+ ext4_lblk_t len;
|
|
|
|
|
|
ex = path[depth].p_ext;
|
|
|
if (ex == NULL) {
|
|
|
/* there is no extent yet, so gap is [0;-] */
|
|
|
- lblock = 0;
|
|
|
+ *lblk = 0;
|
|
|
len = EXT_MAX_BLOCKS;
|
|
|
- ext_debug("cache gap(whole file):");
|
|
|
- } else if (block < le32_to_cpu(ex->ee_block)) {
|
|
|
- lblock = block;
|
|
|
- len = le32_to_cpu(ex->ee_block) - block;
|
|
|
- ext_debug("cache gap(before): %u [%u:%u]",
|
|
|
- block,
|
|
|
- le32_to_cpu(ex->ee_block),
|
|
|
- ext4_ext_get_actual_len(ex));
|
|
|
- } else if (block >= le32_to_cpu(ex->ee_block)
|
|
|
+ } else if (*lblk < le32_to_cpu(ex->ee_block)) {
|
|
|
+ len = le32_to_cpu(ex->ee_block) - *lblk;
|
|
|
+ } else if (*lblk >= le32_to_cpu(ex->ee_block)
|
|
|
+ ext4_ext_get_actual_len(ex)) {
|
|
|
ext4_lblk_t next;
|
|
|
- lblock = le32_to_cpu(ex->ee_block)
|
|
|
- + ext4_ext_get_actual_len(ex);
|
|
|
|
|
|
+ *lblk = le32_to_cpu(ex->ee_block) + ext4_ext_get_actual_len(ex);
|
|
|
next = ext4_ext_next_allocated_block(path);
|
|
|
- ext_debug("cache gap(after): [%u:%u] %u",
|
|
|
- le32_to_cpu(ex->ee_block),
|
|
|
- ext4_ext_get_actual_len(ex),
|
|
|
- block);
|
|
|
- BUG_ON(next == lblock);
|
|
|
- len = next - lblock;
|
|
|
+ BUG_ON(next == *lblk);
|
|
|
+ len = next - *lblk;
|
|
|
} else {
|
|
|
BUG();
|
|
|
}
|
|
|
+ return len;
|
|
|
+}
|
|
|
|
|
|
- ext4_es_find_delayed_extent_range(inode, lblock, lblock + len - 1, &es);
|
|
|
+/*
|
|
|
+ * ext4_ext_put_gap_in_cache:
|
|
|
+ * calculate boundaries of the gap that the requested block fits into
|
|
|
+ * and cache this gap
|
|
|
+ */
|
|
|
+static void
|
|
|
+ext4_ext_put_gap_in_cache(struct inode *inode, ext4_lblk_t hole_start,
|
|
|
+ ext4_lblk_t hole_len)
|
|
|
+{
|
|
|
+ struct extent_status es;
|
|
|
+
|
|
|
+ ext4_es_find_delayed_extent_range(inode, hole_start,
|
|
|
+ hole_start + hole_len - 1, &es);
|
|
|
if (es.es_len) {
|
|
|
/* There's delayed extent containing lblock? */
|
|
|
- if (es.es_lblk <= lblock)
|
|
|
+ if (es.es_lblk <= hole_start)
|
|
|
return;
|
|
|
- len = min(es.es_lblk - lblock, len);
|
|
|
+ hole_len = min(es.es_lblk - hole_start, hole_len);
|
|
|
}
|
|
|
- ext_debug(" -> %u:%u\n", lblock, len);
|
|
|
- ext4_es_insert_extent(inode, lblock, len, ~0, EXTENT_STATUS_HOLE);
|
|
|
+ ext_debug(" -> %u:%u\n", hole_start, hole_len);
|
|
|
+ ext4_es_insert_extent(inode, hole_start, hole_len, ~0,
|
|
|
+ EXTENT_STATUS_HOLE);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -4362,11 +4372,15 @@ int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
|
|
|
* we couldn't try to create block if create flag is zero
|
|
|
*/
|
|
|
if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
|
|
|
+ ext4_lblk_t hole_start, hole_len;
|
|
|
+
|
|
|
/*
|
|
|
* put just found gap into cache to speed up
|
|
|
* subsequent requests
|
|
|
*/
|
|
|
- ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
|
|
|
+ hole_start = map->m_lblk;
|
|
|
+ hole_len = ext4_ext_determine_hole(inode, path, &hole_start);
|
|
|
+ ext4_ext_put_gap_in_cache(inode, hole_start, hole_len);
|
|
|
goto out2;
|
|
|
}
|
|
|
|