aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Chen <lchen@suse.com>2018-11-02 18:48:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2018-11-03 13:09:37 -0400
commit6194ae4242dec0c9d604bc05df83aa9260a899e4 (patch)
tree12cadc6b8451443150465c1c26a3792697a4257e
parent3a3d1e51042895c58d4797831921c940b28d8c4b (diff)
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: Larry Chen <lchen@suse.com> Reviewed-by: Andrew 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: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--fs/ocfs2/move_extents.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 7eb3b0a6347e..3f1685d7d43b 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -25,6 +25,7 @@
25#include "ocfs2_ioctl.h" 25#include "ocfs2_ioctl.h"
26 26
27#include "alloc.h" 27#include "alloc.h"
28#include "localalloc.h"
28#include "aops.h" 29#include "aops.h"
29#include "dlmglue.h" 30#include "dlmglue.h"
30#include "extent_map.h" 31#include "extent_map.h"
@@ -233,6 +234,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
233 struct ocfs2_refcount_tree *ref_tree = NULL; 234 struct ocfs2_refcount_tree *ref_tree = NULL;
234 u32 new_phys_cpos, new_len; 235 u32 new_phys_cpos, new_len;
235 u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos); 236 u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
237 int need_free = 0;
236 238
237 if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) { 239 if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
238 BUG_ON(!ocfs2_is_refcount_inode(inode)); 240 BUG_ON(!ocfs2_is_refcount_inode(inode));
@@ -308,6 +310,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
308 if (!partial) { 310 if (!partial) {
309 context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE; 311 context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
310 ret = -ENOSPC; 312 ret = -ENOSPC;
313 need_free = 1;
311 goto out_commit; 314 goto out_commit;
312 } 315 }
313 } 316 }
@@ -332,6 +335,20 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
332 mlog_errno(ret); 335 mlog_errno(ret);
333 336
334out_commit: 337out_commit:
338 if (need_free && context->data_ac) {
339 struct ocfs2_alloc_context *data_ac = context->data_ac;
340
341 if (context->data_ac->ac_which == OCFS2_AC_USE_LOCAL)
342 ocfs2_free_local_alloc_bits(osb, handle, data_ac,
343 new_phys_cpos, new_len);
344 else
345 ocfs2_free_clusters(handle,
346 data_ac->ac_inode,
347 data_ac->ac_bh,
348 ocfs2_clusters_to_blocks(osb->sb, new_phys_cpos),
349 new_len);
350 }
351
335 ocfs2_commit_trans(osb, handle); 352 ocfs2_commit_trans(osb, handle);
336 353
337out_unlock_mutex: 354out_unlock_mutex: