Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6194ae42 authored by Larry Chen's avatar Larry Chen Committed by Linus Torvalds
Browse files

ocfs2: fix clusters leak in ocfs2_defrag_extent()

ocfs2_defrag_extent() might leak allocated clusters.  When the file
system has insufficient space, the number of claimed clusters might be
less than the caller wants.  If that happens, the original code might
directly commit the transaction without returning clusters.

This patch is based on code in ocfs2_add_clusters_in_btree().

[akpm@linux-foundation.org: include localalloc.h, reduce scope of data_ac]
Link: http://lkml.kernel.org/r/20180904041621.16874-3-lchen@suse.com


Signed-off-by: default avatarLarry Chen <lchen@suse.com>
Reviewed-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Cc: Mark Fasheh <mark@fasheh.com>
Cc: Joel Becker <jlbec@evilplan.org>
Cc: Junxiao Bi <junxiao.bi@oracle.com>
Cc: Joseph Qi <jiangqi903@gmail.com>
Cc: Changwei Ge <ge.changwei@h3c.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3a3d1e51
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@
#include "ocfs2_ioctl.h"

#include "alloc.h"
#include "localalloc.h"
#include "aops.h"
#include "dlmglue.h"
#include "extent_map.h"
@@ -233,6 +234,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
	struct ocfs2_refcount_tree *ref_tree = NULL;
	u32 new_phys_cpos, new_len;
	u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
	int need_free = 0;

	if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
		BUG_ON(!ocfs2_is_refcount_inode(inode));
@@ -308,6 +310,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
		if (!partial) {
			context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
			ret = -ENOSPC;
			need_free = 1;
			goto out_commit;
		}
	}
@@ -332,6 +335,20 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
		mlog_errno(ret);

out_commit:
	if (need_free && context->data_ac) {
		struct ocfs2_alloc_context *data_ac = context->data_ac;

		if (context->data_ac->ac_which == OCFS2_AC_USE_LOCAL)
			ocfs2_free_local_alloc_bits(osb, handle, data_ac,
					new_phys_cpos, new_len);
		else
			ocfs2_free_clusters(handle,
					data_ac->ac_inode,
					data_ac->ac_bh,
					ocfs2_clusters_to_blocks(osb->sb, new_phys_cpos),
					new_len);
	}

	ocfs2_commit_trans(osb, handle);

out_unlock_mutex: