|
@@ -2212,6 +2212,8 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define EXT4_EXT_ZERO_LEN 7
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* This function is called by ext4_ext_get_blocks() if someone tries to write
|
|
* This function is called by ext4_ext_get_blocks() if someone tries to write
|
|
* to an uninitialized extent. It may result in splitting the uninitialized
|
|
* to an uninitialized extent. It may result in splitting the uninitialized
|
|
@@ -2254,6 +2256,18 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
err = ext4_ext_get_access(handle, inode, path + depth);
|
|
if (err)
|
|
if (err)
|
|
goto out;
|
|
goto out;
|
|
|
|
+ /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */
|
|
|
|
+ if (ee_len <= 2*EXT4_EXT_ZERO_LEN) {
|
|
|
|
+ err = ext4_ext_zeroout(inode, &orig_ex);
|
|
|
|
+ if (err)
|
|
|
|
+ goto fix_extent_len;
|
|
|
|
+ /* update the extent length and mark as initialized */
|
|
|
|
+ ex->ee_block = orig_ex.ee_block;
|
|
|
|
+ ex->ee_len = orig_ex.ee_len;
|
|
|
|
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
|
|
|
+ ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
+ return le16_to_cpu(ex->ee_len);
|
|
|
|
+ }
|
|
|
|
|
|
/* ex1: ee_block to iblock - 1 : uninitialized */
|
|
/* ex1: ee_block to iblock - 1 : uninitialized */
|
|
if (iblock > ee_block) {
|
|
if (iblock > ee_block) {
|
|
@@ -2272,6 +2286,38 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
|
/* ex3: to ee_block + ee_len : uninitialised */
|
|
/* ex3: to ee_block + ee_len : uninitialised */
|
|
if (allocated > max_blocks) {
|
|
if (allocated > max_blocks) {
|
|
unsigned int newdepth;
|
|
unsigned int newdepth;
|
|
|
|
+ /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
|
|
|
|
+ if (allocated <= EXT4_EXT_ZERO_LEN) {
|
|
|
|
+ /* Mark first half uninitialized.
|
|
|
|
+ * Mark second half initialized and zero out the
|
|
|
|
+ * initialized extent
|
|
|
|
+ */
|
|
|
|
+ ex->ee_block = orig_ex.ee_block;
|
|
|
|
+ ex->ee_len = cpu_to_le16(ee_len - allocated);
|
|
|
|
+ ext4_ext_mark_uninitialized(ex);
|
|
|
|
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
|
|
|
+ ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
+
|
|
|
|
+ ex3 = &newex;
|
|
|
|
+ ex3->ee_block = cpu_to_le32(iblock);
|
|
|
|
+ ext4_ext_store_pblock(ex3, newblock);
|
|
|
|
+ ex3->ee_len = cpu_to_le16(allocated);
|
|
|
|
+ err = ext4_ext_insert_extent(handle, inode, path, ex3);
|
|
|
|
+ if (err == -ENOSPC) {
|
|
|
|
+ err = ext4_ext_zeroout(inode, &orig_ex);
|
|
|
|
+ if (err)
|
|
|
|
+ goto fix_extent_len;
|
|
|
|
+ ex->ee_block = orig_ex.ee_block;
|
|
|
|
+ ex->ee_len = orig_ex.ee_len;
|
|
|
|
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
|
|
|
+ ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
+ return le16_to_cpu(ex->ee_len);
|
|
|
|
+
|
|
|
|
+ } else if (err)
|
|
|
|
+ goto fix_extent_len;
|
|
|
|
+
|
|
|
|
+ return allocated;
|
|
|
|
+ }
|
|
ex3 = &newex;
|
|
ex3 = &newex;
|
|
ex3->ee_block = cpu_to_le32(iblock + max_blocks);
|
|
ex3->ee_block = cpu_to_le32(iblock + max_blocks);
|
|
ext4_ext_store_pblock(ex3, newblock + max_blocks);
|
|
ext4_ext_store_pblock(ex3, newblock + max_blocks);
|
|
@@ -2320,6 +2366,23 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
allocated = max_blocks;
|
|
allocated = max_blocks;
|
|
|
|
+
|
|
|
|
+ /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
|
|
|
|
+ * to insert a extent in the middle zerout directly
|
|
|
|
+ * otherwise give the extent a chance to merge to left
|
|
|
|
+ */
|
|
|
|
+ if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
|
|
|
|
+ iblock != ee_block) {
|
|
|
|
+ err = ext4_ext_zeroout(inode, &orig_ex);
|
|
|
|
+ if (err)
|
|
|
|
+ goto fix_extent_len;
|
|
|
|
+ /* update the extent length and mark as initialized */
|
|
|
|
+ ex->ee_block = orig_ex.ee_block;
|
|
|
|
+ ex->ee_len = orig_ex.ee_len;
|
|
|
|
+ ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
|
|
|
|
+ ext4_ext_dirty(handle, inode, path + depth);
|
|
|
|
+ return le16_to_cpu(ex->ee_len);
|
|
|
|
+ }
|
|
}
|
|
}
|
|
/*
|
|
/*
|
|
* If there was a change of depth as part of the
|
|
* If there was a change of depth as part of the
|