|
@@ -1813,39 +1813,101 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
|
|
|
}
|
|
|
depth = ext_depth(inode);
|
|
|
ex = path[depth].p_ext;
|
|
|
+ eh = path[depth].p_hdr;
|
|
|
if (unlikely(path[depth].p_hdr == NULL)) {
|
|
|
EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
|
|
|
return -EIO;
|
|
|
}
|
|
|
|
|
|
/* try to insert block into found extent and return */
|
|
|
- if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)
|
|
|
- && ext4_can_extents_be_merged(inode, ex, newext)) {
|
|
|
- ext_debug("append [%d]%d block to %u:[%d]%d (from %llu)\n",
|
|
|
- ext4_ext_is_uninitialized(newext),
|
|
|
- ext4_ext_get_actual_len(newext),
|
|
|
- le32_to_cpu(ex->ee_block),
|
|
|
- ext4_ext_is_uninitialized(ex),
|
|
|
- ext4_ext_get_actual_len(ex),
|
|
|
- ext4_ext_pblock(ex));
|
|
|
- err = ext4_ext_get_access(handle, inode, path + depth);
|
|
|
- if (err)
|
|
|
- return err;
|
|
|
+ if (ex && !(flag & EXT4_GET_BLOCKS_PRE_IO)) {
|
|
|
|
|
|
/*
|
|
|
- * ext4_can_extents_be_merged should have checked that either
|
|
|
- * both extents are uninitialized, or both aren't. Thus we
|
|
|
- * need to check only one of them here.
|
|
|
+ * Try to see whether we should rather test the extent on
|
|
|
+ * right from ex, or from the left of ex. This is because
|
|
|
+ * ext4_ext_find_extent() can return either extent on the
|
|
|
+ * left, or on the right from the searched position. This
|
|
|
+ * will make merging more effective.
|
|
|
*/
|
|
|
- if (ext4_ext_is_uninitialized(ex))
|
|
|
- uninitialized = 1;
|
|
|
- ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
|
|
+ if (ex < EXT_LAST_EXTENT(eh) &&
|
|
|
+ (le32_to_cpu(ex->ee_block) +
|
|
|
+ ext4_ext_get_actual_len(ex) <
|
|
|
+ le32_to_cpu(newext->ee_block))) {
|
|
|
+ ex += 1;
|
|
|
+ goto prepend;
|
|
|
+ } else if ((ex > EXT_FIRST_EXTENT(eh)) &&
|
|
|
+ (le32_to_cpu(newext->ee_block) +
|
|
|
+ ext4_ext_get_actual_len(newext) <
|
|
|
+ le32_to_cpu(ex->ee_block)))
|
|
|
+ ex -= 1;
|
|
|
+
|
|
|
+ /* Try to append newex to the ex */
|
|
|
+ if (ext4_can_extents_be_merged(inode, ex, newext)) {
|
|
|
+ ext_debug("append [%d]%d block to %u:[%d]%d"
|
|
|
+ "(from %llu)\n",
|
|
|
+ ext4_ext_is_uninitialized(newext),
|
|
|
+ ext4_ext_get_actual_len(newext),
|
|
|
+ le32_to_cpu(ex->ee_block),
|
|
|
+ ext4_ext_is_uninitialized(ex),
|
|
|
+ ext4_ext_get_actual_len(ex),
|
|
|
+ ext4_ext_pblock(ex));
|
|
|
+ err = ext4_ext_get_access(handle, inode,
|
|
|
+ path + depth);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ext4_can_extents_be_merged should have checked
|
|
|
+ * that either both extents are uninitialized, or
|
|
|
+ * both aren't. Thus we need to check only one of
|
|
|
+ * them here.
|
|
|
+ */
|
|
|
+ if (ext4_ext_is_uninitialized(ex))
|
|
|
+ uninitialized = 1;
|
|
|
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
|
|
+ ext4_ext_get_actual_len(newext));
|
|
|
- if (uninitialized)
|
|
|
- ext4_ext_mark_uninitialized(ex);
|
|
|
- eh = path[depth].p_hdr;
|
|
|
- nearex = ex;
|
|
|
- goto merge;
|
|
|
+ if (uninitialized)
|
|
|
+ ext4_ext_mark_uninitialized(ex);
|
|
|
+ eh = path[depth].p_hdr;
|
|
|
+ nearex = ex;
|
|
|
+ goto merge;
|
|
|
+ }
|
|
|
+
|
|
|
+prepend:
|
|
|
+ /* Try to prepend newex to the ex */
|
|
|
+ if (ext4_can_extents_be_merged(inode, newext, ex)) {
|
|
|
+ ext_debug("prepend %u[%d]%d block to %u:[%d]%d"
|
|
|
+ "(from %llu)\n",
|
|
|
+ le32_to_cpu(newext->ee_block),
|
|
|
+ ext4_ext_is_uninitialized(newext),
|
|
|
+ ext4_ext_get_actual_len(newext),
|
|
|
+ le32_to_cpu(ex->ee_block),
|
|
|
+ ext4_ext_is_uninitialized(ex),
|
|
|
+ ext4_ext_get_actual_len(ex),
|
|
|
+ ext4_ext_pblock(ex));
|
|
|
+ err = ext4_ext_get_access(handle, inode,
|
|
|
+ path + depth);
|
|
|
+ if (err)
|
|
|
+ return err;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * ext4_can_extents_be_merged should have checked
|
|
|
+ * that either both extents are uninitialized, or
|
|
|
+ * both aren't. Thus we need to check only one of
|
|
|
+ * them here.
|
|
|
+ */
|
|
|
+ if (ext4_ext_is_uninitialized(ex))
|
|
|
+ uninitialized = 1;
|
|
|
+ ex->ee_block = newext->ee_block;
|
|
|
+ ext4_ext_store_pblock(ex, ext4_ext_pblock(newext));
|
|
|
+ ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)
|
|
|
+ + ext4_ext_get_actual_len(newext));
|
|
|
+ if (uninitialized)
|
|
|
+ ext4_ext_mark_uninitialized(ex);
|
|
|
+ eh = path[depth].p_hdr;
|
|
|
+ nearex = ex;
|
|
|
+ goto merge;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
depth = ext_depth(inode);
|