ocfs2: fix clusters leak in ocfs2_defrag_extent()
[ Upstream commit 6194ae4242dec0c9d604bc05df83aa9260a899e4 ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
6c150df9c2
commit
0d3b9ac284
1 changed files with 17 additions and 0 deletions
|
@ -25,6 +25,7 @@
|
||||||
#include "ocfs2_ioctl.h"
|
#include "ocfs2_ioctl.h"
|
||||||
|
|
||||||
#include "alloc.h"
|
#include "alloc.h"
|
||||||
|
#include "localalloc.h"
|
||||||
#include "aops.h"
|
#include "aops.h"
|
||||||
#include "dlmglue.h"
|
#include "dlmglue.h"
|
||||||
#include "extent_map.h"
|
#include "extent_map.h"
|
||||||
|
@ -222,6 +223,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
|
||||||
struct ocfs2_refcount_tree *ref_tree = NULL;
|
struct ocfs2_refcount_tree *ref_tree = NULL;
|
||||||
u32 new_phys_cpos, new_len;
|
u32 new_phys_cpos, new_len;
|
||||||
u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
|
u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
|
||||||
|
int need_free = 0;
|
||||||
|
|
||||||
if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
|
if ((ext_flags & OCFS2_EXT_REFCOUNTED) && *len) {
|
||||||
BUG_ON(!ocfs2_is_refcount_inode(inode));
|
BUG_ON(!ocfs2_is_refcount_inode(inode));
|
||||||
|
@ -312,6 +314,7 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
|
||||||
if (!partial) {
|
if (!partial) {
|
||||||
context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
|
context->range->me_flags &= ~OCFS2_MOVE_EXT_FL_COMPLETE;
|
||||||
ret = -ENOSPC;
|
ret = -ENOSPC;
|
||||||
|
need_free = 1;
|
||||||
goto out_commit;
|
goto out_commit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -336,6 +339,20 @@ static int ocfs2_defrag_extent(struct ocfs2_move_extents_context *context,
|
||||||
mlog_errno(ret);
|
mlog_errno(ret);
|
||||||
|
|
||||||
out_commit:
|
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);
|
ocfs2_commit_trans(osb, handle);
|
||||||
|
|
||||||
out_unlock_mutex:
|
out_unlock_mutex:
|
||||||
|
|
Loading…
Reference in a new issue