Unverified Commit ed5a5304 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!3601 xfs: fix perag leak when growfs fails

Merge Pull Request from: @ci-robot 
 
PR sync from: Long Li <leo.lilong@huawei.com>
https://mailweb.openeuler.org/hyperkitty/list/kernel@openeuler.org/message/SK7F4FROQV7Q3ZVGAM5SZW4QK52Q3YZV/ 
This patch set fix perag leak problems when growfs fails.

Long Li (2):
  xfs: add lock protection when remove perag from radix tree
  xfs: fix perag leak when growfs fails


-- 
2.31.1
 
https://gitee.com/openeuler/kernel/issues/I8RJA8 
 
Link:https://gitee.com/openeuler/kernel/pulls/3601

 

Reviewed-by: default avatarzhangyi (F) <yi.zhang@huawei.com>
Signed-off-by: default avatarZheng Zengkai <zhengzengkai@huawei.com>
parents 6f62149a af078748
Loading
Loading
Loading
Loading
+28 −8
Original line number Diff line number Diff line
@@ -332,6 +332,31 @@ xfs_agino_range(
	return __xfs_agino_range(mp, xfs_ag_block_count(mp, agno), first, last);
}

/*
 * Free perag within the specified AG range, it is only used to free unused
 * perags under the error handling path.
 */
void
xfs_free_unused_perag_range(
	struct xfs_mount	*mp,
	xfs_agnumber_t		agstart,
	xfs_agnumber_t		agend)
{
	struct xfs_perag	*pag;
	xfs_agnumber_t		index;

	for (index = agstart; index < agend; index++) {
		spin_lock(&mp->m_perag_lock);
		pag = radix_tree_delete(&mp->m_perag_tree, index);
		spin_unlock(&mp->m_perag_lock);
		if (!pag)
			break;
		xfs_buf_hash_destroy(pag);
		xfs_defer_drain_free(&pag->pag_intents_drain);
		kmem_free(pag);
	}
}

int
xfs_initialize_perag(
	struct xfs_mount	*mp,
@@ -424,19 +449,14 @@ xfs_initialize_perag(

out_remove_pag:
	xfs_defer_drain_free(&pag->pag_intents_drain);
	spin_lock(&mp->m_perag_lock);
	radix_tree_delete(&mp->m_perag_tree, index);
	spin_unlock(&mp->m_perag_lock);
out_free_pag:
	kmem_free(pag);
out_unwind_new_pags:
	/* unwind any prior newly initialized pags */
	for (index = first_initialised; index < agcount; index++) {
		pag = radix_tree_delete(&mp->m_perag_tree, index);
		if (!pag)
			break;
		xfs_buf_hash_destroy(pag);
		xfs_defer_drain_free(&pag->pag_intents_drain);
		kmem_free(pag);
	}
	xfs_free_unused_perag_range(mp, first_initialised, agcount);
	return error;
}

+2 −0
Original line number Diff line number Diff line
@@ -133,6 +133,8 @@ __XFS_AG_OPSTATE(prefers_metadata, PREFERS_METADATA)
__XFS_AG_OPSTATE(allows_inodes, ALLOWS_INODES)
__XFS_AG_OPSTATE(agfl_needs_reset, AGFL_NEEDS_RESET)

void xfs_free_unused_perag_range(struct xfs_mount *mp, xfs_agnumber_t agstart,
			xfs_agnumber_t agend);
int xfs_initialize_perag(struct xfs_mount *mp, xfs_agnumber_t agcount,
			xfs_rfsblock_t dcount, xfs_agnumber_t *maxagi);
int xfs_initialize_perag_data(struct xfs_mount *mp, xfs_agnumber_t agno);
+4 −1
Original line number Diff line number Diff line
@@ -153,7 +153,7 @@ xfs_growfs_data_private(
		error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growdata, -delta, 0,
				0, &tp);
	if (error)
		return error;
		goto out_free_unused_perag;

	last_pag = xfs_perag_get(mp, oagcount - 1);
	if (delta > 0) {
@@ -227,6 +227,9 @@ xfs_growfs_data_private(

out_trans_cancel:
	xfs_trans_cancel(tp);
out_free_unused_perag:
	if (nagcount > oagcount)
		xfs_free_unused_perag_range(mp, oagcount, nagcount);
	return error;
}