[Devel,RHEL7,COMMIT] ext4: Discard preallocated block before swap_extents

Submitted by Konstantin Khorenko on Oct. 14, 2016, 10:16 p.m.

Details

Message ID 201610142216.u9EMGMnd028257@finist_cl7.x64_64.work.ct
State New
Series "ext4: Discard preallocated block before swap_extents"
Headers show

Commit Message

Konstantin Khorenko Oct. 14, 2016, 10:16 p.m.
The commit is pushed to "branch-rh7-3.10.0-327.36.1.vz7.19.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-327.36.1.vz7.19.1
------>
commit adb6ff95974228cb22b72ab950504d46586196ac
Author: Dmitry Monakhov <dmonakhov@openvz.org>
Date:   Sat Oct 15 02:14:03 2016 +0400

    ext4: Discard preallocated block before swap_extents
    
    Inode preallocation consists of two parts (used and unused) fully controlled
    by inode, so it must be discarded before swap extents.
    Currently we may skip drop_preallocation if file is sparse.
    
    This patch does:
    - Moves ext4_discard_preallocations to ext4_swap_extents.
      This makes more readable and reliable for future changes.
    - Cleanup main move_extent loop
    
    xfstests:ext4/024 (pended: https://github.com/dmonakhov/xfstests/commit/7a4763963f73ea5d5bba45eefa484494aa3df7cf)
    
    Signed-off-by: Dmitry Monakhov <dmonakhov@openvz.org>
    Reviewed-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
    
    khorenko@:
    v2: return changed moved_len only in case ioctl succeeds, otherwise
        leave it intact.
---
 fs/ext4/extents.c     |  2 ++
 fs/ext4/move_extent.c | 20 ++++++++------------
 2 files changed, 10 insertions(+), 12 deletions(-)

Patch hide | download patch | download mbox

diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
index 71b4b620..381cd54 100644
--- a/fs/ext4/extents.c
+++ b/fs/ext4/extents.c
@@ -5574,9 +5574,11 @@  ext4_swap_extents(handle_t *handle, struct inode *inode1,
 	BUG_ON(!mutex_is_locked(&inode1->i_mutex));
 	BUG_ON(!mutex_is_locked(&inode2->i_mutex));
 
+	ext4_discard_preallocations(inode1);
 	*erp = ext4_es_remove_extent(inode1, lblk1, count);
 	if (unlikely(*erp))
 		return 0;
+	ext4_discard_preallocations(inode2);
 	*erp = ext4_es_remove_extent(inode2, lblk2, count);
 	if (unlikely(*erp))
 		return 0;
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index cdf5017..5029de7 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -551,6 +551,7 @@  ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 	ext4_lblk_t o_end, o_start = orig_blk;
 	ext4_lblk_t d_start = donor_blk;
 	int ret;
+	__u64 m_len = *moved_len;
 
 	if (orig_inode->i_sb != donor_inode->i_sb) {
 		ext4_debug("ext4 move extent: The argument files "
@@ -607,7 +608,7 @@  ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 
 		ret = get_ext_path(orig_inode, o_start, &path);
 		if (ret)
-			goto out;
+			break;
 		ex = path[path->p_depth].p_ext;
 		next_blk = ext4_ext_next_allocated_block(path);
 		cur_blk = le32_to_cpu(ex->ee_block);
@@ -617,7 +618,7 @@  ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 			if (next_blk == EXT_MAX_BLOCKS) {
 				o_start = o_end;
 				ret = -ENODATA;
-				goto out;
+				break;
 			}
 			d_start += next_blk - o_start;
 			o_start = next_blk;
@@ -629,7 +630,7 @@  ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 			o_start = cur_blk;
 			/* Extent inside requested range ?*/
 			if (cur_blk >= o_end)
-				goto out;
+				break;
 		} else { /* in_range(o_start, o_blk, o_len) */
 			cur_len += cur_blk - o_start;
 		}
@@ -662,17 +663,12 @@  ext4_move_extents(struct file *o_filp, struct file *d_filp, __u64 orig_blk,
 			break;
 		o_start += cur_len;
 		d_start += cur_len;
+		m_len += cur_len;
 	}
-	*moved_len = o_start - orig_blk;
-	if (*moved_len > len)
-		*moved_len = len;
-
 out:
-	if (*moved_len) {
-		ext4_discard_preallocations(orig_inode);
-		ext4_discard_preallocations(donor_inode);
-	}
-
+	WARN_ON(m_len > len);
+	if (ret == 0)
+		*moved_len = m_len;
 	ext4_ext_drop_refs(path);
 	kfree(path);
 	ext4_double_up_write_data_sem(orig_inode, donor_inode);