162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2013 Jie Liu.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "xfs.h"
762306a36Sopenharmony_ci#include "xfs_fs.h"
862306a36Sopenharmony_ci#include "xfs_shared.h"
962306a36Sopenharmony_ci#include "xfs_format.h"
1062306a36Sopenharmony_ci#include "xfs_log_format.h"
1162306a36Sopenharmony_ci#include "xfs_trans_resv.h"
1262306a36Sopenharmony_ci#include "xfs_mount.h"
1362306a36Sopenharmony_ci#include "xfs_da_format.h"
1462306a36Sopenharmony_ci#include "xfs_trans_space.h"
1562306a36Sopenharmony_ci#include "xfs_da_btree.h"
1662306a36Sopenharmony_ci#include "xfs_bmap_btree.h"
1762306a36Sopenharmony_ci#include "xfs_trace.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Calculate the maximum length in bytes that would be required for a local
2162306a36Sopenharmony_ci * attribute value as large attributes out of line are not logged.
2262306a36Sopenharmony_ci */
2362306a36Sopenharmony_ciSTATIC int
2462306a36Sopenharmony_cixfs_log_calc_max_attrsetm_res(
2562306a36Sopenharmony_ci	struct xfs_mount	*mp)
2662306a36Sopenharmony_ci{
2762306a36Sopenharmony_ci	int			size;
2862306a36Sopenharmony_ci	int			nblks;
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci	size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) -
3162306a36Sopenharmony_ci	       MAXNAMELEN - 1;
3262306a36Sopenharmony_ci	nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
3362306a36Sopenharmony_ci	nblks += XFS_B_TO_FSB(mp, size);
3462306a36Sopenharmony_ci	nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return  M_RES(mp)->tr_attrsetm.tr_logres +
3762306a36Sopenharmony_ci		M_RES(mp)->tr_attrsetrt.tr_logres * nblks;
3862306a36Sopenharmony_ci}
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci/*
4162306a36Sopenharmony_ci * Compute an alternate set of log reservation sizes for use exclusively with
4262306a36Sopenharmony_ci * minimum log size calculations.
4362306a36Sopenharmony_ci */
4462306a36Sopenharmony_cistatic void
4562306a36Sopenharmony_cixfs_log_calc_trans_resv_for_minlogblocks(
4662306a36Sopenharmony_ci	struct xfs_mount	*mp,
4762306a36Sopenharmony_ci	struct xfs_trans_resv	*resv)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	unsigned int		rmap_maxlevels = mp->m_rmap_maxlevels;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	/*
5262306a36Sopenharmony_ci	 * In the early days of rmap+reflink, we always set the rmap maxlevels
5362306a36Sopenharmony_ci	 * to 9 even if the AG was small enough that it would never grow to
5462306a36Sopenharmony_ci	 * that height.  Transaction reservation sizes influence the minimum
5562306a36Sopenharmony_ci	 * log size calculation, which influences the size of the log that mkfs
5662306a36Sopenharmony_ci	 * creates.  Use the old value here to ensure that newly formatted
5762306a36Sopenharmony_ci	 * small filesystems will mount on older kernels.
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci	if (xfs_has_rmapbt(mp) && xfs_has_reflink(mp))
6062306a36Sopenharmony_ci		mp->m_rmap_maxlevels = XFS_OLD_REFLINK_RMAP_MAXLEVELS;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	xfs_trans_resv_calc(mp, resv);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (xfs_has_reflink(mp)) {
6562306a36Sopenharmony_ci		/*
6662306a36Sopenharmony_ci		 * In the early days of reflink, typical log operation counts
6762306a36Sopenharmony_ci		 * were greatly overestimated.
6862306a36Sopenharmony_ci		 */
6962306a36Sopenharmony_ci		resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
7062306a36Sopenharmony_ci		resv->tr_itruncate.tr_logcount =
7162306a36Sopenharmony_ci				XFS_ITRUNCATE_LOG_COUNT_REFLINK;
7262306a36Sopenharmony_ci		resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT_REFLINK;
7362306a36Sopenharmony_ci	} else if (xfs_has_rmapbt(mp)) {
7462306a36Sopenharmony_ci		/*
7562306a36Sopenharmony_ci		 * In the early days of non-reflink rmap, the impact of rmapbt
7662306a36Sopenharmony_ci		 * updates on log counts were not taken into account at all.
7762306a36Sopenharmony_ci		 */
7862306a36Sopenharmony_ci		resv->tr_write.tr_logcount = XFS_WRITE_LOG_COUNT;
7962306a36Sopenharmony_ci		resv->tr_itruncate.tr_logcount = XFS_ITRUNCATE_LOG_COUNT;
8062306a36Sopenharmony_ci		resv->tr_qm_dqalloc.tr_logcount = XFS_WRITE_LOG_COUNT;
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/*
8462306a36Sopenharmony_ci	 * In the early days of reflink, we did not use deferred refcount
8562306a36Sopenharmony_ci	 * update log items, so log reservations must be recomputed using the
8662306a36Sopenharmony_ci	 * old calculations.
8762306a36Sopenharmony_ci	 */
8862306a36Sopenharmony_ci	resv->tr_write.tr_logres =
8962306a36Sopenharmony_ci			xfs_calc_write_reservation_minlogsize(mp);
9062306a36Sopenharmony_ci	resv->tr_itruncate.tr_logres =
9162306a36Sopenharmony_ci			xfs_calc_itruncate_reservation_minlogsize(mp);
9262306a36Sopenharmony_ci	resv->tr_qm_dqalloc.tr_logres =
9362306a36Sopenharmony_ci			xfs_calc_qm_dqalloc_reservation_minlogsize(mp);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	/* Put everything back the way it was.  This goes at the end. */
9662306a36Sopenharmony_ci	mp->m_rmap_maxlevels = rmap_maxlevels;
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/*
10062306a36Sopenharmony_ci * Iterate over the log space reservation table to figure out and return
10162306a36Sopenharmony_ci * the maximum one in terms of the pre-calculated values which were done
10262306a36Sopenharmony_ci * at mount time.
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_civoid
10562306a36Sopenharmony_cixfs_log_get_max_trans_res(
10662306a36Sopenharmony_ci	struct xfs_mount	*mp,
10762306a36Sopenharmony_ci	struct xfs_trans_res	*max_resp)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct xfs_trans_resv	resv = {};
11062306a36Sopenharmony_ci	struct xfs_trans_res	*resp;
11162306a36Sopenharmony_ci	struct xfs_trans_res	*end_resp;
11262306a36Sopenharmony_ci	unsigned int		i;
11362306a36Sopenharmony_ci	int			log_space = 0;
11462306a36Sopenharmony_ci	int			attr_space;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	attr_space = xfs_log_calc_max_attrsetm_res(mp);
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	xfs_log_calc_trans_resv_for_minlogblocks(mp, &resv);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	resp = (struct xfs_trans_res *)&resv;
12162306a36Sopenharmony_ci	end_resp = (struct xfs_trans_res *)(&resv + 1);
12262306a36Sopenharmony_ci	for (i = 0; resp < end_resp; i++, resp++) {
12362306a36Sopenharmony_ci		int		tmp = resp->tr_logcount > 1 ?
12462306a36Sopenharmony_ci				      resp->tr_logres * resp->tr_logcount :
12562306a36Sopenharmony_ci				      resp->tr_logres;
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		trace_xfs_trans_resv_calc_minlogsize(mp, i, resp);
12862306a36Sopenharmony_ci		if (log_space < tmp) {
12962306a36Sopenharmony_ci			log_space = tmp;
13062306a36Sopenharmony_ci			*max_resp = *resp;		/* struct copy */
13162306a36Sopenharmony_ci		}
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	if (attr_space > log_space) {
13562306a36Sopenharmony_ci		*max_resp = resv.tr_attrsetm;	/* struct copy */
13662306a36Sopenharmony_ci		max_resp->tr_logres = attr_space;
13762306a36Sopenharmony_ci	}
13862306a36Sopenharmony_ci	trace_xfs_log_get_max_trans_res(mp, max_resp);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * Calculate the minimum valid log size for the given superblock configuration.
14362306a36Sopenharmony_ci * Used to calculate the minimum log size at mkfs time, and to determine if
14462306a36Sopenharmony_ci * the log is large enough or not at mount time. Returns the minimum size in
14562306a36Sopenharmony_ci * filesystem block size units.
14662306a36Sopenharmony_ci */
14762306a36Sopenharmony_ciint
14862306a36Sopenharmony_cixfs_log_calc_minimum_size(
14962306a36Sopenharmony_ci	struct xfs_mount	*mp)
15062306a36Sopenharmony_ci{
15162306a36Sopenharmony_ci	struct xfs_trans_res	tres = {0};
15262306a36Sopenharmony_ci	int			max_logres;
15362306a36Sopenharmony_ci	int			min_logblks = 0;
15462306a36Sopenharmony_ci	int			lsunit = 0;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	xfs_log_get_max_trans_res(mp, &tres);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres);
15962306a36Sopenharmony_ci	if (tres.tr_logcount > 1)
16062306a36Sopenharmony_ci		max_logres *= tres.tr_logcount;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	if (xfs_has_logv2(mp) && mp->m_sb.sb_logsunit > 1)
16362306a36Sopenharmony_ci		lsunit = BTOBB(mp->m_sb.sb_logsunit);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Two factors should be taken into account for calculating the minimum
16762306a36Sopenharmony_ci	 * log space.
16862306a36Sopenharmony_ci	 * 1) The fundamental limitation is that no single transaction can be
16962306a36Sopenharmony_ci	 *    larger than half size of the log.
17062306a36Sopenharmony_ci	 *
17162306a36Sopenharmony_ci	 *    From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR
17262306a36Sopenharmony_ci	 *    define, which is set to 3. That means we can definitely fit
17362306a36Sopenharmony_ci	 *    maximally sized 2 transactions in the log. We'll use this same
17462306a36Sopenharmony_ci	 *    value here.
17562306a36Sopenharmony_ci	 *
17662306a36Sopenharmony_ci	 * 2) If the lsunit option is specified, a transaction requires 2 LSU
17762306a36Sopenharmony_ci	 *    for the reservation because there are two log writes that can
17862306a36Sopenharmony_ci	 *    require padding - the transaction data and the commit record which
17962306a36Sopenharmony_ci	 *    are written separately and both can require padding to the LSU.
18062306a36Sopenharmony_ci	 *    Consider that we can have an active CIL reservation holding 2*LSU,
18162306a36Sopenharmony_ci	 *    but the CIL is not over a push threshold, in this case, if we
18262306a36Sopenharmony_ci	 *    don't have enough log space for at one new transaction, which
18362306a36Sopenharmony_ci	 *    includes another 2*LSU in the reservation, we will run into dead
18462306a36Sopenharmony_ci	 *    loop situation in log space grant procedure. i.e.
18562306a36Sopenharmony_ci	 *    xlog_grant_head_wait().
18662306a36Sopenharmony_ci	 *
18762306a36Sopenharmony_ci	 *    Hence the log size needs to be able to contain two maximally sized
18862306a36Sopenharmony_ci	 *    and padded transactions, which is (2 * (2 * LSU + maxlres)).
18962306a36Sopenharmony_ci	 *
19062306a36Sopenharmony_ci	 * Also, the log size should be a multiple of the log stripe unit, round
19162306a36Sopenharmony_ci	 * it up to lsunit boundary if lsunit is specified.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	if (lsunit) {
19462306a36Sopenharmony_ci		min_logblks = roundup_64(BTOBB(max_logres), lsunit) +
19562306a36Sopenharmony_ci			      2 * lsunit;
19662306a36Sopenharmony_ci	} else
19762306a36Sopenharmony_ci		min_logblks = BTOBB(max_logres) + 2 * BBSIZE;
19862306a36Sopenharmony_ci	min_logblks *= XFS_MIN_LOG_FACTOR;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	return XFS_BB_TO_FSB(mp, min_logblks);
20162306a36Sopenharmony_ci}
202