162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc.
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_bit.h"
1362306a36Sopenharmony_ci#include "xfs_mount.h"
1462306a36Sopenharmony_ci#include "xfs_inode.h"
1562306a36Sopenharmony_ci#include "xfs_bmap.h"
1662306a36Sopenharmony_ci#include "xfs_bmap_btree.h"
1762306a36Sopenharmony_ci#include "xfs_trans.h"
1862306a36Sopenharmony_ci#include "xfs_trans_space.h"
1962306a36Sopenharmony_ci#include "xfs_icache.h"
2062306a36Sopenharmony_ci#include "xfs_rtalloc.h"
2162306a36Sopenharmony_ci#include "xfs_sb.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci/*
2462306a36Sopenharmony_ci * Read and return the summary information for a given extent size,
2562306a36Sopenharmony_ci * bitmap block combination.
2662306a36Sopenharmony_ci * Keeps track of a current summary block, so we don't keep reading
2762306a36Sopenharmony_ci * it from the buffer cache.
2862306a36Sopenharmony_ci */
2962306a36Sopenharmony_cistatic int
3062306a36Sopenharmony_cixfs_rtget_summary(
3162306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount structure */
3262306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
3362306a36Sopenharmony_ci	int		log,		/* log2 of extent size */
3462306a36Sopenharmony_ci	xfs_rtblock_t	bbno,		/* bitmap block number */
3562306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
3662306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
3762306a36Sopenharmony_ci	xfs_suminfo_t	*sum)		/* out: summary info for this block */
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	return xfs_rtmodify_summary_int(mp, tp, log, bbno, 0, rbpp, rsb, sum);
4062306a36Sopenharmony_ci}
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci/*
4362306a36Sopenharmony_ci * Return whether there are any free extents in the size range given
4462306a36Sopenharmony_ci * by low and high, for the bitmap block bbno.
4562306a36Sopenharmony_ci */
4662306a36Sopenharmony_ciSTATIC int				/* error */
4762306a36Sopenharmony_cixfs_rtany_summary(
4862306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount structure */
4962306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
5062306a36Sopenharmony_ci	int		low,		/* low log2 extent size */
5162306a36Sopenharmony_ci	int		high,		/* high log2 extent size */
5262306a36Sopenharmony_ci	xfs_rtblock_t	bbno,		/* bitmap block number */
5362306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
5462306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
5562306a36Sopenharmony_ci	int		*stat)		/* out: any good extents here? */
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int		error;		/* error value */
5862306a36Sopenharmony_ci	int		log;		/* loop counter, log2 of ext. size */
5962306a36Sopenharmony_ci	xfs_suminfo_t	sum;		/* summary data */
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci	/* There are no extents at levels < m_rsum_cache[bbno]. */
6262306a36Sopenharmony_ci	if (mp->m_rsum_cache && low < mp->m_rsum_cache[bbno])
6362306a36Sopenharmony_ci		low = mp->m_rsum_cache[bbno];
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * Loop over logs of extent sizes.
6762306a36Sopenharmony_ci	 */
6862306a36Sopenharmony_ci	for (log = low; log <= high; log++) {
6962306a36Sopenharmony_ci		/*
7062306a36Sopenharmony_ci		 * Get one summary datum.
7162306a36Sopenharmony_ci		 */
7262306a36Sopenharmony_ci		error = xfs_rtget_summary(mp, tp, log, bbno, rbpp, rsb, &sum);
7362306a36Sopenharmony_ci		if (error) {
7462306a36Sopenharmony_ci			return error;
7562306a36Sopenharmony_ci		}
7662306a36Sopenharmony_ci		/*
7762306a36Sopenharmony_ci		 * If there are any, return success.
7862306a36Sopenharmony_ci		 */
7962306a36Sopenharmony_ci		if (sum) {
8062306a36Sopenharmony_ci			*stat = 1;
8162306a36Sopenharmony_ci			goto out;
8262306a36Sopenharmony_ci		}
8362306a36Sopenharmony_ci	}
8462306a36Sopenharmony_ci	/*
8562306a36Sopenharmony_ci	 * Found nothing, return failure.
8662306a36Sopenharmony_ci	 */
8762306a36Sopenharmony_ci	*stat = 0;
8862306a36Sopenharmony_ciout:
8962306a36Sopenharmony_ci	/* There were no extents at levels < log. */
9062306a36Sopenharmony_ci	if (mp->m_rsum_cache && log > mp->m_rsum_cache[bbno])
9162306a36Sopenharmony_ci		mp->m_rsum_cache[bbno] = log;
9262306a36Sopenharmony_ci	return 0;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci/*
9762306a36Sopenharmony_ci * Copy and transform the summary file, given the old and new
9862306a36Sopenharmony_ci * parameters in the mount structures.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_ciSTATIC int				/* error */
10162306a36Sopenharmony_cixfs_rtcopy_summary(
10262306a36Sopenharmony_ci	xfs_mount_t	*omp,		/* old file system mount point */
10362306a36Sopenharmony_ci	xfs_mount_t	*nmp,		/* new file system mount point */
10462306a36Sopenharmony_ci	xfs_trans_t	*tp)		/* transaction pointer */
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	xfs_rtblock_t	bbno;		/* bitmap block number */
10762306a36Sopenharmony_ci	struct xfs_buf	*bp;		/* summary buffer */
10862306a36Sopenharmony_ci	int		error;		/* error return value */
10962306a36Sopenharmony_ci	int		log;		/* summary level number (log length) */
11062306a36Sopenharmony_ci	xfs_suminfo_t	sum;		/* summary data */
11162306a36Sopenharmony_ci	xfs_fsblock_t	sumbno;		/* summary block number */
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci	bp = NULL;
11462306a36Sopenharmony_ci	for (log = omp->m_rsumlevels - 1; log >= 0; log--) {
11562306a36Sopenharmony_ci		for (bbno = omp->m_sb.sb_rbmblocks - 1;
11662306a36Sopenharmony_ci		     (xfs_srtblock_t)bbno >= 0;
11762306a36Sopenharmony_ci		     bbno--) {
11862306a36Sopenharmony_ci			error = xfs_rtget_summary(omp, tp, log, bbno, &bp,
11962306a36Sopenharmony_ci				&sumbno, &sum);
12062306a36Sopenharmony_ci			if (error)
12162306a36Sopenharmony_ci				return error;
12262306a36Sopenharmony_ci			if (sum == 0)
12362306a36Sopenharmony_ci				continue;
12462306a36Sopenharmony_ci			error = xfs_rtmodify_summary(omp, tp, log, bbno, -sum,
12562306a36Sopenharmony_ci				&bp, &sumbno);
12662306a36Sopenharmony_ci			if (error)
12762306a36Sopenharmony_ci				return error;
12862306a36Sopenharmony_ci			error = xfs_rtmodify_summary(nmp, tp, log, bbno, sum,
12962306a36Sopenharmony_ci				&bp, &sumbno);
13062306a36Sopenharmony_ci			if (error)
13162306a36Sopenharmony_ci				return error;
13262306a36Sopenharmony_ci			ASSERT(sum > 0);
13362306a36Sopenharmony_ci		}
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci	return 0;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * Mark an extent specified by start and len allocated.
13962306a36Sopenharmony_ci * Updates all the summary information as well as the bitmap.
14062306a36Sopenharmony_ci */
14162306a36Sopenharmony_ciSTATIC int				/* error */
14262306a36Sopenharmony_cixfs_rtallocate_range(
14362306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
14462306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
14562306a36Sopenharmony_ci	xfs_rtblock_t	start,		/* start block to allocate */
14662306a36Sopenharmony_ci	xfs_extlen_t	len,		/* length to allocate */
14762306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
14862306a36Sopenharmony_ci	xfs_fsblock_t	*rsb)		/* in/out: summary block number */
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	xfs_rtblock_t	end;		/* end of the allocated extent */
15162306a36Sopenharmony_ci	int		error;		/* error value */
15262306a36Sopenharmony_ci	xfs_rtblock_t	postblock = 0;	/* first block allocated > end */
15362306a36Sopenharmony_ci	xfs_rtblock_t	preblock = 0;	/* first block allocated < start */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	end = start + len - 1;
15662306a36Sopenharmony_ci	/*
15762306a36Sopenharmony_ci	 * Assume we're allocating out of the middle of a free extent.
15862306a36Sopenharmony_ci	 * We need to find the beginning and end of the extent so we can
15962306a36Sopenharmony_ci	 * properly update the summary.
16062306a36Sopenharmony_ci	 */
16162306a36Sopenharmony_ci	error = xfs_rtfind_back(mp, tp, start, 0, &preblock);
16262306a36Sopenharmony_ci	if (error) {
16362306a36Sopenharmony_ci		return error;
16462306a36Sopenharmony_ci	}
16562306a36Sopenharmony_ci	/*
16662306a36Sopenharmony_ci	 * Find the next allocated block (end of free extent).
16762306a36Sopenharmony_ci	 */
16862306a36Sopenharmony_ci	error = xfs_rtfind_forw(mp, tp, end, mp->m_sb.sb_rextents - 1,
16962306a36Sopenharmony_ci		&postblock);
17062306a36Sopenharmony_ci	if (error) {
17162306a36Sopenharmony_ci		return error;
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci	/*
17462306a36Sopenharmony_ci	 * Decrement the summary information corresponding to the entire
17562306a36Sopenharmony_ci	 * (old) free extent.
17662306a36Sopenharmony_ci	 */
17762306a36Sopenharmony_ci	error = xfs_rtmodify_summary(mp, tp,
17862306a36Sopenharmony_ci		XFS_RTBLOCKLOG(postblock + 1 - preblock),
17962306a36Sopenharmony_ci		XFS_BITTOBLOCK(mp, preblock), -1, rbpp, rsb);
18062306a36Sopenharmony_ci	if (error) {
18162306a36Sopenharmony_ci		return error;
18262306a36Sopenharmony_ci	}
18362306a36Sopenharmony_ci	/*
18462306a36Sopenharmony_ci	 * If there are blocks not being allocated at the front of the
18562306a36Sopenharmony_ci	 * old extent, add summary data for them to be free.
18662306a36Sopenharmony_ci	 */
18762306a36Sopenharmony_ci	if (preblock < start) {
18862306a36Sopenharmony_ci		error = xfs_rtmodify_summary(mp, tp,
18962306a36Sopenharmony_ci			XFS_RTBLOCKLOG(start - preblock),
19062306a36Sopenharmony_ci			XFS_BITTOBLOCK(mp, preblock), 1, rbpp, rsb);
19162306a36Sopenharmony_ci		if (error) {
19262306a36Sopenharmony_ci			return error;
19362306a36Sopenharmony_ci		}
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci	/*
19662306a36Sopenharmony_ci	 * If there are blocks not being allocated at the end of the
19762306a36Sopenharmony_ci	 * old extent, add summary data for them to be free.
19862306a36Sopenharmony_ci	 */
19962306a36Sopenharmony_ci	if (postblock > end) {
20062306a36Sopenharmony_ci		error = xfs_rtmodify_summary(mp, tp,
20162306a36Sopenharmony_ci			XFS_RTBLOCKLOG(postblock - end),
20262306a36Sopenharmony_ci			XFS_BITTOBLOCK(mp, end + 1), 1, rbpp, rsb);
20362306a36Sopenharmony_ci		if (error) {
20462306a36Sopenharmony_ci			return error;
20562306a36Sopenharmony_ci		}
20662306a36Sopenharmony_ci	}
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * Modify the bitmap to mark this extent allocated.
20962306a36Sopenharmony_ci	 */
21062306a36Sopenharmony_ci	error = xfs_rtmodify_range(mp, tp, start, len, 0);
21162306a36Sopenharmony_ci	return error;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/*
21562306a36Sopenharmony_ci * Make sure we don't run off the end of the rt volume.  Be careful that
21662306a36Sopenharmony_ci * adjusting maxlen downwards doesn't cause us to fail the alignment checks.
21762306a36Sopenharmony_ci */
21862306a36Sopenharmony_cistatic inline xfs_extlen_t
21962306a36Sopenharmony_cixfs_rtallocate_clamp_len(
22062306a36Sopenharmony_ci	struct xfs_mount	*mp,
22162306a36Sopenharmony_ci	xfs_rtblock_t		startrtx,
22262306a36Sopenharmony_ci	xfs_extlen_t		rtxlen,
22362306a36Sopenharmony_ci	xfs_extlen_t		prod)
22462306a36Sopenharmony_ci{
22562306a36Sopenharmony_ci	xfs_extlen_t		ret;
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	ret = min(mp->m_sb.sb_rextents, startrtx + rtxlen) - startrtx;
22862306a36Sopenharmony_ci	return rounddown(ret, prod);
22962306a36Sopenharmony_ci}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci/*
23262306a36Sopenharmony_ci * Attempt to allocate an extent minlen<=len<=maxlen starting from
23362306a36Sopenharmony_ci * bitmap block bbno.  If we don't get maxlen then use prod to trim
23462306a36Sopenharmony_ci * the length, if given.  Returns error; returns starting block in *rtblock.
23562306a36Sopenharmony_ci * The lengths are all in rtextents.
23662306a36Sopenharmony_ci */
23762306a36Sopenharmony_ciSTATIC int				/* error */
23862306a36Sopenharmony_cixfs_rtallocate_extent_block(
23962306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
24062306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
24162306a36Sopenharmony_ci	xfs_rtblock_t	bbno,		/* bitmap block number */
24262306a36Sopenharmony_ci	xfs_extlen_t	minlen,		/* minimum length to allocate */
24362306a36Sopenharmony_ci	xfs_extlen_t	maxlen,		/* maximum length to allocate */
24462306a36Sopenharmony_ci	xfs_extlen_t	*len,		/* out: actual length allocated */
24562306a36Sopenharmony_ci	xfs_rtblock_t	*nextp,		/* out: next block to try */
24662306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
24762306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
24862306a36Sopenharmony_ci	xfs_extlen_t	prod,		/* extent product factor */
24962306a36Sopenharmony_ci	xfs_rtblock_t	*rtblock)	/* out: start block allocated */
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	xfs_rtblock_t	besti;		/* best rtblock found so far */
25262306a36Sopenharmony_ci	xfs_rtblock_t	bestlen;	/* best length found so far */
25362306a36Sopenharmony_ci	xfs_rtblock_t	end;		/* last rtblock in chunk */
25462306a36Sopenharmony_ci	int		error;		/* error value */
25562306a36Sopenharmony_ci	xfs_rtblock_t	i;		/* current rtblock trying */
25662306a36Sopenharmony_ci	xfs_rtblock_t	next;		/* next rtblock to try */
25762306a36Sopenharmony_ci	int		stat;		/* status from internal calls */
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/*
26062306a36Sopenharmony_ci	 * Loop over all the extents starting in this bitmap block,
26162306a36Sopenharmony_ci	 * looking for one that's long enough.
26262306a36Sopenharmony_ci	 */
26362306a36Sopenharmony_ci	for (i = XFS_BLOCKTOBIT(mp, bbno), besti = -1, bestlen = 0,
26462306a36Sopenharmony_ci		end = XFS_BLOCKTOBIT(mp, bbno + 1) - 1;
26562306a36Sopenharmony_ci	     i <= end;
26662306a36Sopenharmony_ci	     i++) {
26762306a36Sopenharmony_ci		/* Make sure we don't scan off the end of the rt volume. */
26862306a36Sopenharmony_ci		maxlen = xfs_rtallocate_clamp_len(mp, i, maxlen, prod);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci		/*
27162306a36Sopenharmony_ci		 * See if there's a free extent of maxlen starting at i.
27262306a36Sopenharmony_ci		 * If it's not so then next will contain the first non-free.
27362306a36Sopenharmony_ci		 */
27462306a36Sopenharmony_ci		error = xfs_rtcheck_range(mp, tp, i, maxlen, 1, &next, &stat);
27562306a36Sopenharmony_ci		if (error) {
27662306a36Sopenharmony_ci			return error;
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci		if (stat) {
27962306a36Sopenharmony_ci			/*
28062306a36Sopenharmony_ci			 * i for maxlen is all free, allocate and return that.
28162306a36Sopenharmony_ci			 */
28262306a36Sopenharmony_ci			error = xfs_rtallocate_range(mp, tp, i, maxlen, rbpp,
28362306a36Sopenharmony_ci				rsb);
28462306a36Sopenharmony_ci			if (error) {
28562306a36Sopenharmony_ci				return error;
28662306a36Sopenharmony_ci			}
28762306a36Sopenharmony_ci			*len = maxlen;
28862306a36Sopenharmony_ci			*rtblock = i;
28962306a36Sopenharmony_ci			return 0;
29062306a36Sopenharmony_ci		}
29162306a36Sopenharmony_ci		/*
29262306a36Sopenharmony_ci		 * In the case where we have a variable-sized allocation
29362306a36Sopenharmony_ci		 * request, figure out how big this free piece is,
29462306a36Sopenharmony_ci		 * and if it's big enough for the minimum, and the best
29562306a36Sopenharmony_ci		 * so far, remember it.
29662306a36Sopenharmony_ci		 */
29762306a36Sopenharmony_ci		if (minlen < maxlen) {
29862306a36Sopenharmony_ci			xfs_rtblock_t	thislen;	/* this extent size */
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci			thislen = next - i;
30162306a36Sopenharmony_ci			if (thislen >= minlen && thislen > bestlen) {
30262306a36Sopenharmony_ci				besti = i;
30362306a36Sopenharmony_ci				bestlen = thislen;
30462306a36Sopenharmony_ci			}
30562306a36Sopenharmony_ci		}
30662306a36Sopenharmony_ci		/*
30762306a36Sopenharmony_ci		 * If not done yet, find the start of the next free space.
30862306a36Sopenharmony_ci		 */
30962306a36Sopenharmony_ci		if (next < end) {
31062306a36Sopenharmony_ci			error = xfs_rtfind_forw(mp, tp, next, end, &i);
31162306a36Sopenharmony_ci			if (error) {
31262306a36Sopenharmony_ci				return error;
31362306a36Sopenharmony_ci			}
31462306a36Sopenharmony_ci		} else
31562306a36Sopenharmony_ci			break;
31662306a36Sopenharmony_ci	}
31762306a36Sopenharmony_ci	/*
31862306a36Sopenharmony_ci	 * Searched the whole thing & didn't find a maxlen free extent.
31962306a36Sopenharmony_ci	 */
32062306a36Sopenharmony_ci	if (minlen < maxlen && besti != -1) {
32162306a36Sopenharmony_ci		xfs_extlen_t	p;	/* amount to trim length by */
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci		/*
32462306a36Sopenharmony_ci		 * If size should be a multiple of prod, make that so.
32562306a36Sopenharmony_ci		 */
32662306a36Sopenharmony_ci		if (prod > 1) {
32762306a36Sopenharmony_ci			div_u64_rem(bestlen, prod, &p);
32862306a36Sopenharmony_ci			if (p)
32962306a36Sopenharmony_ci				bestlen -= p;
33062306a36Sopenharmony_ci		}
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci		/*
33362306a36Sopenharmony_ci		 * Allocate besti for bestlen & return that.
33462306a36Sopenharmony_ci		 */
33562306a36Sopenharmony_ci		error = xfs_rtallocate_range(mp, tp, besti, bestlen, rbpp, rsb);
33662306a36Sopenharmony_ci		if (error) {
33762306a36Sopenharmony_ci			return error;
33862306a36Sopenharmony_ci		}
33962306a36Sopenharmony_ci		*len = bestlen;
34062306a36Sopenharmony_ci		*rtblock = besti;
34162306a36Sopenharmony_ci		return 0;
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci	/*
34462306a36Sopenharmony_ci	 * Allocation failed.  Set *nextp to the next block to try.
34562306a36Sopenharmony_ci	 */
34662306a36Sopenharmony_ci	*nextp = next;
34762306a36Sopenharmony_ci	*rtblock = NULLRTBLOCK;
34862306a36Sopenharmony_ci	return 0;
34962306a36Sopenharmony_ci}
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci/*
35262306a36Sopenharmony_ci * Allocate an extent of length minlen<=len<=maxlen, starting at block
35362306a36Sopenharmony_ci * bno.  If we don't get maxlen then use prod to trim the length, if given.
35462306a36Sopenharmony_ci * Returns error; returns starting block in *rtblock.
35562306a36Sopenharmony_ci * The lengths are all in rtextents.
35662306a36Sopenharmony_ci */
35762306a36Sopenharmony_ciSTATIC int				/* error */
35862306a36Sopenharmony_cixfs_rtallocate_extent_exact(
35962306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
36062306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
36162306a36Sopenharmony_ci	xfs_rtblock_t	bno,		/* starting block number to allocate */
36262306a36Sopenharmony_ci	xfs_extlen_t	minlen,		/* minimum length to allocate */
36362306a36Sopenharmony_ci	xfs_extlen_t	maxlen,		/* maximum length to allocate */
36462306a36Sopenharmony_ci	xfs_extlen_t	*len,		/* out: actual length allocated */
36562306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
36662306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
36762306a36Sopenharmony_ci	xfs_extlen_t	prod,		/* extent product factor */
36862306a36Sopenharmony_ci	xfs_rtblock_t	*rtblock)	/* out: start block allocated */
36962306a36Sopenharmony_ci{
37062306a36Sopenharmony_ci	int		error;		/* error value */
37162306a36Sopenharmony_ci	xfs_extlen_t	i;		/* extent length trimmed due to prod */
37262306a36Sopenharmony_ci	int		isfree;		/* extent is free */
37362306a36Sopenharmony_ci	xfs_rtblock_t	next;		/* next block to try (dummy) */
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	ASSERT(minlen % prod == 0);
37662306a36Sopenharmony_ci	ASSERT(maxlen % prod == 0);
37762306a36Sopenharmony_ci	/*
37862306a36Sopenharmony_ci	 * Check if the range in question (for maxlen) is free.
37962306a36Sopenharmony_ci	 */
38062306a36Sopenharmony_ci	error = xfs_rtcheck_range(mp, tp, bno, maxlen, 1, &next, &isfree);
38162306a36Sopenharmony_ci	if (error) {
38262306a36Sopenharmony_ci		return error;
38362306a36Sopenharmony_ci	}
38462306a36Sopenharmony_ci	if (isfree) {
38562306a36Sopenharmony_ci		/*
38662306a36Sopenharmony_ci		 * If it is, allocate it and return success.
38762306a36Sopenharmony_ci		 */
38862306a36Sopenharmony_ci		error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
38962306a36Sopenharmony_ci		if (error) {
39062306a36Sopenharmony_ci			return error;
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci		*len = maxlen;
39362306a36Sopenharmony_ci		*rtblock = bno;
39462306a36Sopenharmony_ci		return 0;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci	/*
39762306a36Sopenharmony_ci	 * If not, allocate what there is, if it's at least minlen.
39862306a36Sopenharmony_ci	 */
39962306a36Sopenharmony_ci	maxlen = next - bno;
40062306a36Sopenharmony_ci	if (maxlen < minlen) {
40162306a36Sopenharmony_ci		/*
40262306a36Sopenharmony_ci		 * Failed, return failure status.
40362306a36Sopenharmony_ci		 */
40462306a36Sopenharmony_ci		*rtblock = NULLRTBLOCK;
40562306a36Sopenharmony_ci		return 0;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci	/*
40862306a36Sopenharmony_ci	 * Trim off tail of extent, if prod is specified.
40962306a36Sopenharmony_ci	 */
41062306a36Sopenharmony_ci	if (prod > 1 && (i = maxlen % prod)) {
41162306a36Sopenharmony_ci		maxlen -= i;
41262306a36Sopenharmony_ci		if (maxlen < minlen) {
41362306a36Sopenharmony_ci			/*
41462306a36Sopenharmony_ci			 * Now we can't do it, return failure status.
41562306a36Sopenharmony_ci			 */
41662306a36Sopenharmony_ci			*rtblock = NULLRTBLOCK;
41762306a36Sopenharmony_ci			return 0;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci	/*
42162306a36Sopenharmony_ci	 * Allocate what we can and return it.
42262306a36Sopenharmony_ci	 */
42362306a36Sopenharmony_ci	error = xfs_rtallocate_range(mp, tp, bno, maxlen, rbpp, rsb);
42462306a36Sopenharmony_ci	if (error) {
42562306a36Sopenharmony_ci		return error;
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci	*len = maxlen;
42862306a36Sopenharmony_ci	*rtblock = bno;
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci/*
43362306a36Sopenharmony_ci * Allocate an extent of length minlen<=len<=maxlen, starting as near
43462306a36Sopenharmony_ci * to bno as possible.  If we don't get maxlen then use prod to trim
43562306a36Sopenharmony_ci * the length, if given.  The lengths are all in rtextents.
43662306a36Sopenharmony_ci */
43762306a36Sopenharmony_ciSTATIC int				/* error */
43862306a36Sopenharmony_cixfs_rtallocate_extent_near(
43962306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
44062306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
44162306a36Sopenharmony_ci	xfs_rtblock_t	bno,		/* starting block number to allocate */
44262306a36Sopenharmony_ci	xfs_extlen_t	minlen,		/* minimum length to allocate */
44362306a36Sopenharmony_ci	xfs_extlen_t	maxlen,		/* maximum length to allocate */
44462306a36Sopenharmony_ci	xfs_extlen_t	*len,		/* out: actual length allocated */
44562306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
44662306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
44762306a36Sopenharmony_ci	xfs_extlen_t	prod,		/* extent product factor */
44862306a36Sopenharmony_ci	xfs_rtblock_t	*rtblock)	/* out: start block allocated */
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	int		any;		/* any useful extents from summary */
45162306a36Sopenharmony_ci	xfs_rtblock_t	bbno;		/* bitmap block number */
45262306a36Sopenharmony_ci	int		error;		/* error value */
45362306a36Sopenharmony_ci	int		i;		/* bitmap block offset (loop control) */
45462306a36Sopenharmony_ci	int		j;		/* secondary loop control */
45562306a36Sopenharmony_ci	int		log2len;	/* log2 of minlen */
45662306a36Sopenharmony_ci	xfs_rtblock_t	n;		/* next block to try */
45762306a36Sopenharmony_ci	xfs_rtblock_t	r;		/* result block */
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	ASSERT(minlen % prod == 0);
46062306a36Sopenharmony_ci	ASSERT(maxlen % prod == 0);
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci	/*
46362306a36Sopenharmony_ci	 * If the block number given is off the end, silently set it to
46462306a36Sopenharmony_ci	 * the last block.
46562306a36Sopenharmony_ci	 */
46662306a36Sopenharmony_ci	if (bno >= mp->m_sb.sb_rextents)
46762306a36Sopenharmony_ci		bno = mp->m_sb.sb_rextents - 1;
46862306a36Sopenharmony_ci
46962306a36Sopenharmony_ci	/* Make sure we don't run off the end of the rt volume. */
47062306a36Sopenharmony_ci	maxlen = xfs_rtallocate_clamp_len(mp, bno, maxlen, prod);
47162306a36Sopenharmony_ci	if (maxlen < minlen) {
47262306a36Sopenharmony_ci		*rtblock = NULLRTBLOCK;
47362306a36Sopenharmony_ci		return 0;
47462306a36Sopenharmony_ci	}
47562306a36Sopenharmony_ci
47662306a36Sopenharmony_ci	/*
47762306a36Sopenharmony_ci	 * Try the exact allocation first.
47862306a36Sopenharmony_ci	 */
47962306a36Sopenharmony_ci	error = xfs_rtallocate_extent_exact(mp, tp, bno, minlen, maxlen, len,
48062306a36Sopenharmony_ci		rbpp, rsb, prod, &r);
48162306a36Sopenharmony_ci	if (error) {
48262306a36Sopenharmony_ci		return error;
48362306a36Sopenharmony_ci	}
48462306a36Sopenharmony_ci	/*
48562306a36Sopenharmony_ci	 * If the exact allocation worked, return that.
48662306a36Sopenharmony_ci	 */
48762306a36Sopenharmony_ci	if (r != NULLRTBLOCK) {
48862306a36Sopenharmony_ci		*rtblock = r;
48962306a36Sopenharmony_ci		return 0;
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci	bbno = XFS_BITTOBLOCK(mp, bno);
49262306a36Sopenharmony_ci	i = 0;
49362306a36Sopenharmony_ci	ASSERT(minlen != 0);
49462306a36Sopenharmony_ci	log2len = xfs_highbit32(minlen);
49562306a36Sopenharmony_ci	/*
49662306a36Sopenharmony_ci	 * Loop over all bitmap blocks (bbno + i is current block).
49762306a36Sopenharmony_ci	 */
49862306a36Sopenharmony_ci	for (;;) {
49962306a36Sopenharmony_ci		/*
50062306a36Sopenharmony_ci		 * Get summary information of extents of all useful levels
50162306a36Sopenharmony_ci		 * starting in this bitmap block.
50262306a36Sopenharmony_ci		 */
50362306a36Sopenharmony_ci		error = xfs_rtany_summary(mp, tp, log2len, mp->m_rsumlevels - 1,
50462306a36Sopenharmony_ci			bbno + i, rbpp, rsb, &any);
50562306a36Sopenharmony_ci		if (error) {
50662306a36Sopenharmony_ci			return error;
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci		/*
50962306a36Sopenharmony_ci		 * If there are any useful extents starting here, try
51062306a36Sopenharmony_ci		 * allocating one.
51162306a36Sopenharmony_ci		 */
51262306a36Sopenharmony_ci		if (any) {
51362306a36Sopenharmony_ci			/*
51462306a36Sopenharmony_ci			 * On the positive side of the starting location.
51562306a36Sopenharmony_ci			 */
51662306a36Sopenharmony_ci			if (i >= 0) {
51762306a36Sopenharmony_ci				/*
51862306a36Sopenharmony_ci				 * Try to allocate an extent starting in
51962306a36Sopenharmony_ci				 * this block.
52062306a36Sopenharmony_ci				 */
52162306a36Sopenharmony_ci				error = xfs_rtallocate_extent_block(mp, tp,
52262306a36Sopenharmony_ci					bbno + i, minlen, maxlen, len, &n, rbpp,
52362306a36Sopenharmony_ci					rsb, prod, &r);
52462306a36Sopenharmony_ci				if (error) {
52562306a36Sopenharmony_ci					return error;
52662306a36Sopenharmony_ci				}
52762306a36Sopenharmony_ci				/*
52862306a36Sopenharmony_ci				 * If it worked, return it.
52962306a36Sopenharmony_ci				 */
53062306a36Sopenharmony_ci				if (r != NULLRTBLOCK) {
53162306a36Sopenharmony_ci					*rtblock = r;
53262306a36Sopenharmony_ci					return 0;
53362306a36Sopenharmony_ci				}
53462306a36Sopenharmony_ci			}
53562306a36Sopenharmony_ci			/*
53662306a36Sopenharmony_ci			 * On the negative side of the starting location.
53762306a36Sopenharmony_ci			 */
53862306a36Sopenharmony_ci			else {		/* i < 0 */
53962306a36Sopenharmony_ci				/*
54062306a36Sopenharmony_ci				 * Loop backwards through the bitmap blocks from
54162306a36Sopenharmony_ci				 * the starting point-1 up to where we are now.
54262306a36Sopenharmony_ci				 * There should be an extent which ends in this
54362306a36Sopenharmony_ci				 * bitmap block and is long enough.
54462306a36Sopenharmony_ci				 */
54562306a36Sopenharmony_ci				for (j = -1; j > i; j--) {
54662306a36Sopenharmony_ci					/*
54762306a36Sopenharmony_ci					 * Grab the summary information for
54862306a36Sopenharmony_ci					 * this bitmap block.
54962306a36Sopenharmony_ci					 */
55062306a36Sopenharmony_ci					error = xfs_rtany_summary(mp, tp,
55162306a36Sopenharmony_ci						log2len, mp->m_rsumlevels - 1,
55262306a36Sopenharmony_ci						bbno + j, rbpp, rsb, &any);
55362306a36Sopenharmony_ci					if (error) {
55462306a36Sopenharmony_ci						return error;
55562306a36Sopenharmony_ci					}
55662306a36Sopenharmony_ci					/*
55762306a36Sopenharmony_ci					 * If there's no extent given in the
55862306a36Sopenharmony_ci					 * summary that means the extent we
55962306a36Sopenharmony_ci					 * found must carry over from an
56062306a36Sopenharmony_ci					 * earlier block.  If there is an
56162306a36Sopenharmony_ci					 * extent given, we've already tried
56262306a36Sopenharmony_ci					 * that allocation, don't do it again.
56362306a36Sopenharmony_ci					 */
56462306a36Sopenharmony_ci					if (any)
56562306a36Sopenharmony_ci						continue;
56662306a36Sopenharmony_ci					error = xfs_rtallocate_extent_block(mp,
56762306a36Sopenharmony_ci						tp, bbno + j, minlen, maxlen,
56862306a36Sopenharmony_ci						len, &n, rbpp, rsb, prod, &r);
56962306a36Sopenharmony_ci					if (error) {
57062306a36Sopenharmony_ci						return error;
57162306a36Sopenharmony_ci					}
57262306a36Sopenharmony_ci					/*
57362306a36Sopenharmony_ci					 * If it works, return the extent.
57462306a36Sopenharmony_ci					 */
57562306a36Sopenharmony_ci					if (r != NULLRTBLOCK) {
57662306a36Sopenharmony_ci						*rtblock = r;
57762306a36Sopenharmony_ci						return 0;
57862306a36Sopenharmony_ci					}
57962306a36Sopenharmony_ci				}
58062306a36Sopenharmony_ci				/*
58162306a36Sopenharmony_ci				 * There weren't intervening bitmap blocks
58262306a36Sopenharmony_ci				 * with a long enough extent, or the
58362306a36Sopenharmony_ci				 * allocation didn't work for some reason
58462306a36Sopenharmony_ci				 * (i.e. it's a little * too short).
58562306a36Sopenharmony_ci				 * Try to allocate from the summary block
58662306a36Sopenharmony_ci				 * that we found.
58762306a36Sopenharmony_ci				 */
58862306a36Sopenharmony_ci				error = xfs_rtallocate_extent_block(mp, tp,
58962306a36Sopenharmony_ci					bbno + i, minlen, maxlen, len, &n, rbpp,
59062306a36Sopenharmony_ci					rsb, prod, &r);
59162306a36Sopenharmony_ci				if (error) {
59262306a36Sopenharmony_ci					return error;
59362306a36Sopenharmony_ci				}
59462306a36Sopenharmony_ci				/*
59562306a36Sopenharmony_ci				 * If it works, return the extent.
59662306a36Sopenharmony_ci				 */
59762306a36Sopenharmony_ci				if (r != NULLRTBLOCK) {
59862306a36Sopenharmony_ci					*rtblock = r;
59962306a36Sopenharmony_ci					return 0;
60062306a36Sopenharmony_ci				}
60162306a36Sopenharmony_ci			}
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci		/*
60462306a36Sopenharmony_ci		 * Loop control.  If we were on the positive side, and there's
60562306a36Sopenharmony_ci		 * still more blocks on the negative side, go there.
60662306a36Sopenharmony_ci		 */
60762306a36Sopenharmony_ci		if (i > 0 && (int)bbno - i >= 0)
60862306a36Sopenharmony_ci			i = -i;
60962306a36Sopenharmony_ci		/*
61062306a36Sopenharmony_ci		 * If positive, and no more negative, but there are more
61162306a36Sopenharmony_ci		 * positive, go there.
61262306a36Sopenharmony_ci		 */
61362306a36Sopenharmony_ci		else if (i > 0 && (int)bbno + i < mp->m_sb.sb_rbmblocks - 1)
61462306a36Sopenharmony_ci			i++;
61562306a36Sopenharmony_ci		/*
61662306a36Sopenharmony_ci		 * If negative or 0 (just started), and there are positive
61762306a36Sopenharmony_ci		 * blocks to go, go there.  The 0 case moves to block 1.
61862306a36Sopenharmony_ci		 */
61962306a36Sopenharmony_ci		else if (i <= 0 && (int)bbno - i < mp->m_sb.sb_rbmblocks - 1)
62062306a36Sopenharmony_ci			i = 1 - i;
62162306a36Sopenharmony_ci		/*
62262306a36Sopenharmony_ci		 * If negative or 0 and there are more negative blocks,
62362306a36Sopenharmony_ci		 * go there.
62462306a36Sopenharmony_ci		 */
62562306a36Sopenharmony_ci		else if (i <= 0 && (int)bbno + i > 0)
62662306a36Sopenharmony_ci			i--;
62762306a36Sopenharmony_ci		/*
62862306a36Sopenharmony_ci		 * Must be done.  Return failure.
62962306a36Sopenharmony_ci		 */
63062306a36Sopenharmony_ci		else
63162306a36Sopenharmony_ci			break;
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci	*rtblock = NULLRTBLOCK;
63462306a36Sopenharmony_ci	return 0;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_ci/*
63862306a36Sopenharmony_ci * Allocate an extent of length minlen<=len<=maxlen, with no position
63962306a36Sopenharmony_ci * specified.  If we don't get maxlen then use prod to trim
64062306a36Sopenharmony_ci * the length, if given.  The lengths are all in rtextents.
64162306a36Sopenharmony_ci */
64262306a36Sopenharmony_ciSTATIC int				/* error */
64362306a36Sopenharmony_cixfs_rtallocate_extent_size(
64462306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
64562306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
64662306a36Sopenharmony_ci	xfs_extlen_t	minlen,		/* minimum length to allocate */
64762306a36Sopenharmony_ci	xfs_extlen_t	maxlen,		/* maximum length to allocate */
64862306a36Sopenharmony_ci	xfs_extlen_t	*len,		/* out: actual length allocated */
64962306a36Sopenharmony_ci	struct xfs_buf	**rbpp,		/* in/out: summary block buffer */
65062306a36Sopenharmony_ci	xfs_fsblock_t	*rsb,		/* in/out: summary block number */
65162306a36Sopenharmony_ci	xfs_extlen_t	prod,		/* extent product factor */
65262306a36Sopenharmony_ci	xfs_rtblock_t	*rtblock)	/* out: start block allocated */
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	int		error;		/* error value */
65562306a36Sopenharmony_ci	int		i;		/* bitmap block number */
65662306a36Sopenharmony_ci	int		l;		/* level number (loop control) */
65762306a36Sopenharmony_ci	xfs_rtblock_t	n;		/* next block to be tried */
65862306a36Sopenharmony_ci	xfs_rtblock_t	r;		/* result block number */
65962306a36Sopenharmony_ci	xfs_suminfo_t	sum;		/* summary information for extents */
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	ASSERT(minlen % prod == 0);
66262306a36Sopenharmony_ci	ASSERT(maxlen % prod == 0);
66362306a36Sopenharmony_ci	ASSERT(maxlen != 0);
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	/*
66662306a36Sopenharmony_ci	 * Loop over all the levels starting with maxlen.
66762306a36Sopenharmony_ci	 * At each level, look at all the bitmap blocks, to see if there
66862306a36Sopenharmony_ci	 * are extents starting there that are long enough (>= maxlen).
66962306a36Sopenharmony_ci	 * Note, only on the initial level can the allocation fail if
67062306a36Sopenharmony_ci	 * the summary says there's an extent.
67162306a36Sopenharmony_ci	 */
67262306a36Sopenharmony_ci	for (l = xfs_highbit32(maxlen); l < mp->m_rsumlevels; l++) {
67362306a36Sopenharmony_ci		/*
67462306a36Sopenharmony_ci		 * Loop over all the bitmap blocks.
67562306a36Sopenharmony_ci		 */
67662306a36Sopenharmony_ci		for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
67762306a36Sopenharmony_ci			/*
67862306a36Sopenharmony_ci			 * Get the summary for this level/block.
67962306a36Sopenharmony_ci			 */
68062306a36Sopenharmony_ci			error = xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
68162306a36Sopenharmony_ci				&sum);
68262306a36Sopenharmony_ci			if (error) {
68362306a36Sopenharmony_ci				return error;
68462306a36Sopenharmony_ci			}
68562306a36Sopenharmony_ci			/*
68662306a36Sopenharmony_ci			 * Nothing there, on to the next block.
68762306a36Sopenharmony_ci			 */
68862306a36Sopenharmony_ci			if (!sum)
68962306a36Sopenharmony_ci				continue;
69062306a36Sopenharmony_ci			/*
69162306a36Sopenharmony_ci			 * Try allocating the extent.
69262306a36Sopenharmony_ci			 */
69362306a36Sopenharmony_ci			error = xfs_rtallocate_extent_block(mp, tp, i, maxlen,
69462306a36Sopenharmony_ci				maxlen, len, &n, rbpp, rsb, prod, &r);
69562306a36Sopenharmony_ci			if (error) {
69662306a36Sopenharmony_ci				return error;
69762306a36Sopenharmony_ci			}
69862306a36Sopenharmony_ci			/*
69962306a36Sopenharmony_ci			 * If it worked, return that.
70062306a36Sopenharmony_ci			 */
70162306a36Sopenharmony_ci			if (r != NULLRTBLOCK) {
70262306a36Sopenharmony_ci				*rtblock = r;
70362306a36Sopenharmony_ci				return 0;
70462306a36Sopenharmony_ci			}
70562306a36Sopenharmony_ci			/*
70662306a36Sopenharmony_ci			 * If the "next block to try" returned from the
70762306a36Sopenharmony_ci			 * allocator is beyond the next bitmap block,
70862306a36Sopenharmony_ci			 * skip to that bitmap block.
70962306a36Sopenharmony_ci			 */
71062306a36Sopenharmony_ci			if (XFS_BITTOBLOCK(mp, n) > i + 1)
71162306a36Sopenharmony_ci				i = XFS_BITTOBLOCK(mp, n) - 1;
71262306a36Sopenharmony_ci		}
71362306a36Sopenharmony_ci	}
71462306a36Sopenharmony_ci	/*
71562306a36Sopenharmony_ci	 * Didn't find any maxlen blocks.  Try smaller ones, unless
71662306a36Sopenharmony_ci	 * we're asking for a fixed size extent.
71762306a36Sopenharmony_ci	 */
71862306a36Sopenharmony_ci	if (minlen > --maxlen) {
71962306a36Sopenharmony_ci		*rtblock = NULLRTBLOCK;
72062306a36Sopenharmony_ci		return 0;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci	ASSERT(minlen != 0);
72362306a36Sopenharmony_ci	ASSERT(maxlen != 0);
72462306a36Sopenharmony_ci
72562306a36Sopenharmony_ci	/*
72662306a36Sopenharmony_ci	 * Loop over sizes, from maxlen down to minlen.
72762306a36Sopenharmony_ci	 * This time, when we do the allocations, allow smaller ones
72862306a36Sopenharmony_ci	 * to succeed.
72962306a36Sopenharmony_ci	 */
73062306a36Sopenharmony_ci	for (l = xfs_highbit32(maxlen); l >= xfs_highbit32(minlen); l--) {
73162306a36Sopenharmony_ci		/*
73262306a36Sopenharmony_ci		 * Loop over all the bitmap blocks, try an allocation
73362306a36Sopenharmony_ci		 * starting in that block.
73462306a36Sopenharmony_ci		 */
73562306a36Sopenharmony_ci		for (i = 0; i < mp->m_sb.sb_rbmblocks; i++) {
73662306a36Sopenharmony_ci			/*
73762306a36Sopenharmony_ci			 * Get the summary information for this level/block.
73862306a36Sopenharmony_ci			 */
73962306a36Sopenharmony_ci			error =	xfs_rtget_summary(mp, tp, l, i, rbpp, rsb,
74062306a36Sopenharmony_ci						  &sum);
74162306a36Sopenharmony_ci			if (error) {
74262306a36Sopenharmony_ci				return error;
74362306a36Sopenharmony_ci			}
74462306a36Sopenharmony_ci			/*
74562306a36Sopenharmony_ci			 * If nothing there, go on to next.
74662306a36Sopenharmony_ci			 */
74762306a36Sopenharmony_ci			if (!sum)
74862306a36Sopenharmony_ci				continue;
74962306a36Sopenharmony_ci			/*
75062306a36Sopenharmony_ci			 * Try the allocation.  Make sure the specified
75162306a36Sopenharmony_ci			 * minlen/maxlen are in the possible range for
75262306a36Sopenharmony_ci			 * this summary level.
75362306a36Sopenharmony_ci			 */
75462306a36Sopenharmony_ci			error = xfs_rtallocate_extent_block(mp, tp, i,
75562306a36Sopenharmony_ci					XFS_RTMAX(minlen, 1 << l),
75662306a36Sopenharmony_ci					XFS_RTMIN(maxlen, (1 << (l + 1)) - 1),
75762306a36Sopenharmony_ci					len, &n, rbpp, rsb, prod, &r);
75862306a36Sopenharmony_ci			if (error) {
75962306a36Sopenharmony_ci				return error;
76062306a36Sopenharmony_ci			}
76162306a36Sopenharmony_ci			/*
76262306a36Sopenharmony_ci			 * If it worked, return that extent.
76362306a36Sopenharmony_ci			 */
76462306a36Sopenharmony_ci			if (r != NULLRTBLOCK) {
76562306a36Sopenharmony_ci				*rtblock = r;
76662306a36Sopenharmony_ci				return 0;
76762306a36Sopenharmony_ci			}
76862306a36Sopenharmony_ci			/*
76962306a36Sopenharmony_ci			 * If the "next block to try" returned from the
77062306a36Sopenharmony_ci			 * allocator is beyond the next bitmap block,
77162306a36Sopenharmony_ci			 * skip to that bitmap block.
77262306a36Sopenharmony_ci			 */
77362306a36Sopenharmony_ci			if (XFS_BITTOBLOCK(mp, n) > i + 1)
77462306a36Sopenharmony_ci				i = XFS_BITTOBLOCK(mp, n) - 1;
77562306a36Sopenharmony_ci		}
77662306a36Sopenharmony_ci	}
77762306a36Sopenharmony_ci	/*
77862306a36Sopenharmony_ci	 * Got nothing, return failure.
77962306a36Sopenharmony_ci	 */
78062306a36Sopenharmony_ci	*rtblock = NULLRTBLOCK;
78162306a36Sopenharmony_ci	return 0;
78262306a36Sopenharmony_ci}
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci/*
78562306a36Sopenharmony_ci * Allocate space to the bitmap or summary file, and zero it, for growfs.
78662306a36Sopenharmony_ci */
78762306a36Sopenharmony_ciSTATIC int
78862306a36Sopenharmony_cixfs_growfs_rt_alloc(
78962306a36Sopenharmony_ci	struct xfs_mount	*mp,		/* file system mount point */
79062306a36Sopenharmony_ci	xfs_extlen_t		oblocks,	/* old count of blocks */
79162306a36Sopenharmony_ci	xfs_extlen_t		nblocks,	/* new count of blocks */
79262306a36Sopenharmony_ci	struct xfs_inode	*ip)		/* inode (bitmap/summary) */
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	xfs_fileoff_t		bno;		/* block number in file */
79562306a36Sopenharmony_ci	struct xfs_buf		*bp;	/* temporary buffer for zeroing */
79662306a36Sopenharmony_ci	xfs_daddr_t		d;		/* disk block address */
79762306a36Sopenharmony_ci	int			error;		/* error return value */
79862306a36Sopenharmony_ci	xfs_fsblock_t		fsbno;		/* filesystem block for bno */
79962306a36Sopenharmony_ci	struct xfs_bmbt_irec	map;		/* block map output */
80062306a36Sopenharmony_ci	int			nmap;		/* number of block maps */
80162306a36Sopenharmony_ci	int			resblks;	/* space reservation */
80262306a36Sopenharmony_ci	enum xfs_blft		buf_type;
80362306a36Sopenharmony_ci	struct xfs_trans	*tp;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	if (ip == mp->m_rsumip)
80662306a36Sopenharmony_ci		buf_type = XFS_BLFT_RTSUMMARY_BUF;
80762306a36Sopenharmony_ci	else
80862306a36Sopenharmony_ci		buf_type = XFS_BLFT_RTBITMAP_BUF;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	/*
81162306a36Sopenharmony_ci	 * Allocate space to the file, as necessary.
81262306a36Sopenharmony_ci	 */
81362306a36Sopenharmony_ci	while (oblocks < nblocks) {
81462306a36Sopenharmony_ci		resblks = XFS_GROWFSRT_SPACE_RES(mp, nblocks - oblocks);
81562306a36Sopenharmony_ci		/*
81662306a36Sopenharmony_ci		 * Reserve space & log for one extent added to the file.
81762306a36Sopenharmony_ci		 */
81862306a36Sopenharmony_ci		error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtalloc, resblks,
81962306a36Sopenharmony_ci				0, 0, &tp);
82062306a36Sopenharmony_ci		if (error)
82162306a36Sopenharmony_ci			return error;
82262306a36Sopenharmony_ci		/*
82362306a36Sopenharmony_ci		 * Lock the inode.
82462306a36Sopenharmony_ci		 */
82562306a36Sopenharmony_ci		xfs_ilock(ip, XFS_ILOCK_EXCL);
82662306a36Sopenharmony_ci		xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci		error = xfs_iext_count_may_overflow(ip, XFS_DATA_FORK,
82962306a36Sopenharmony_ci				XFS_IEXT_ADD_NOSPLIT_CNT);
83062306a36Sopenharmony_ci		if (error == -EFBIG)
83162306a36Sopenharmony_ci			error = xfs_iext_count_upgrade(tp, ip,
83262306a36Sopenharmony_ci					XFS_IEXT_ADD_NOSPLIT_CNT);
83362306a36Sopenharmony_ci		if (error)
83462306a36Sopenharmony_ci			goto out_trans_cancel;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci		/*
83762306a36Sopenharmony_ci		 * Allocate blocks to the bitmap file.
83862306a36Sopenharmony_ci		 */
83962306a36Sopenharmony_ci		nmap = 1;
84062306a36Sopenharmony_ci		error = xfs_bmapi_write(tp, ip, oblocks, nblocks - oblocks,
84162306a36Sopenharmony_ci					XFS_BMAPI_METADATA, 0, &map, &nmap);
84262306a36Sopenharmony_ci		if (!error && nmap < 1)
84362306a36Sopenharmony_ci			error = -ENOSPC;
84462306a36Sopenharmony_ci		if (error)
84562306a36Sopenharmony_ci			goto out_trans_cancel;
84662306a36Sopenharmony_ci		/*
84762306a36Sopenharmony_ci		 * Free any blocks freed up in the transaction, then commit.
84862306a36Sopenharmony_ci		 */
84962306a36Sopenharmony_ci		error = xfs_trans_commit(tp);
85062306a36Sopenharmony_ci		if (error)
85162306a36Sopenharmony_ci			return error;
85262306a36Sopenharmony_ci		/*
85362306a36Sopenharmony_ci		 * Now we need to clear the allocated blocks.
85462306a36Sopenharmony_ci		 * Do this one block per transaction, to keep it simple.
85562306a36Sopenharmony_ci		 */
85662306a36Sopenharmony_ci		for (bno = map.br_startoff, fsbno = map.br_startblock;
85762306a36Sopenharmony_ci		     bno < map.br_startoff + map.br_blockcount;
85862306a36Sopenharmony_ci		     bno++, fsbno++) {
85962306a36Sopenharmony_ci			/*
86062306a36Sopenharmony_ci			 * Reserve log for one block zeroing.
86162306a36Sopenharmony_ci			 */
86262306a36Sopenharmony_ci			error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtzero,
86362306a36Sopenharmony_ci					0, 0, 0, &tp);
86462306a36Sopenharmony_ci			if (error)
86562306a36Sopenharmony_ci				return error;
86662306a36Sopenharmony_ci			/*
86762306a36Sopenharmony_ci			 * Lock the bitmap inode.
86862306a36Sopenharmony_ci			 */
86962306a36Sopenharmony_ci			xfs_ilock(ip, XFS_ILOCK_EXCL);
87062306a36Sopenharmony_ci			xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL);
87162306a36Sopenharmony_ci			/*
87262306a36Sopenharmony_ci			 * Get a buffer for the block.
87362306a36Sopenharmony_ci			 */
87462306a36Sopenharmony_ci			d = XFS_FSB_TO_DADDR(mp, fsbno);
87562306a36Sopenharmony_ci			error = xfs_trans_get_buf(tp, mp->m_ddev_targp, d,
87662306a36Sopenharmony_ci					mp->m_bsize, 0, &bp);
87762306a36Sopenharmony_ci			if (error)
87862306a36Sopenharmony_ci				goto out_trans_cancel;
87962306a36Sopenharmony_ci
88062306a36Sopenharmony_ci			xfs_trans_buf_set_type(tp, bp, buf_type);
88162306a36Sopenharmony_ci			bp->b_ops = &xfs_rtbuf_ops;
88262306a36Sopenharmony_ci			memset(bp->b_addr, 0, mp->m_sb.sb_blocksize);
88362306a36Sopenharmony_ci			xfs_trans_log_buf(tp, bp, 0, mp->m_sb.sb_blocksize - 1);
88462306a36Sopenharmony_ci			/*
88562306a36Sopenharmony_ci			 * Commit the transaction.
88662306a36Sopenharmony_ci			 */
88762306a36Sopenharmony_ci			error = xfs_trans_commit(tp);
88862306a36Sopenharmony_ci			if (error)
88962306a36Sopenharmony_ci				return error;
89062306a36Sopenharmony_ci		}
89162306a36Sopenharmony_ci		/*
89262306a36Sopenharmony_ci		 * Go on to the next extent, if any.
89362306a36Sopenharmony_ci		 */
89462306a36Sopenharmony_ci		oblocks = map.br_startoff + map.br_blockcount;
89562306a36Sopenharmony_ci	}
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	return 0;
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_ciout_trans_cancel:
90062306a36Sopenharmony_ci	xfs_trans_cancel(tp);
90162306a36Sopenharmony_ci	return error;
90262306a36Sopenharmony_ci}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_cistatic void
90562306a36Sopenharmony_cixfs_alloc_rsum_cache(
90662306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount structure */
90762306a36Sopenharmony_ci	xfs_extlen_t	rbmblocks)	/* number of rt bitmap blocks */
90862306a36Sopenharmony_ci{
90962306a36Sopenharmony_ci	/*
91062306a36Sopenharmony_ci	 * The rsum cache is initialized to all zeroes, which is trivially a
91162306a36Sopenharmony_ci	 * lower bound on the minimum level with any free extents. We can
91262306a36Sopenharmony_ci	 * continue without the cache if it couldn't be allocated.
91362306a36Sopenharmony_ci	 */
91462306a36Sopenharmony_ci	mp->m_rsum_cache = kvzalloc(rbmblocks, GFP_KERNEL);
91562306a36Sopenharmony_ci	if (!mp->m_rsum_cache)
91662306a36Sopenharmony_ci		xfs_warn(mp, "could not allocate realtime summary cache");
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci/*
92062306a36Sopenharmony_ci * Visible (exported) functions.
92162306a36Sopenharmony_ci */
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci/*
92462306a36Sopenharmony_ci * Grow the realtime area of the filesystem.
92562306a36Sopenharmony_ci */
92662306a36Sopenharmony_ciint
92762306a36Sopenharmony_cixfs_growfs_rt(
92862306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* mount point for filesystem */
92962306a36Sopenharmony_ci	xfs_growfs_rt_t	*in)		/* growfs rt input struct */
93062306a36Sopenharmony_ci{
93162306a36Sopenharmony_ci	xfs_rtblock_t	bmbno;		/* bitmap block number */
93262306a36Sopenharmony_ci	struct xfs_buf	*bp;		/* temporary buffer */
93362306a36Sopenharmony_ci	int		error;		/* error return value */
93462306a36Sopenharmony_ci	xfs_mount_t	*nmp;		/* new (fake) mount structure */
93562306a36Sopenharmony_ci	xfs_rfsblock_t	nrblocks;	/* new number of realtime blocks */
93662306a36Sopenharmony_ci	xfs_extlen_t	nrbmblocks;	/* new number of rt bitmap blocks */
93762306a36Sopenharmony_ci	xfs_rtblock_t	nrextents;	/* new number of realtime extents */
93862306a36Sopenharmony_ci	uint8_t		nrextslog;	/* new log2 of sb_rextents */
93962306a36Sopenharmony_ci	xfs_extlen_t	nrsumblocks;	/* new number of summary blocks */
94062306a36Sopenharmony_ci	uint		nrsumlevels;	/* new rt summary levels */
94162306a36Sopenharmony_ci	uint		nrsumsize;	/* new size of rt summary, bytes */
94262306a36Sopenharmony_ci	xfs_sb_t	*nsbp;		/* new superblock */
94362306a36Sopenharmony_ci	xfs_extlen_t	rbmblocks;	/* current number of rt bitmap blocks */
94462306a36Sopenharmony_ci	xfs_extlen_t	rsumblocks;	/* current number of rt summary blks */
94562306a36Sopenharmony_ci	xfs_sb_t	*sbp;		/* old superblock */
94662306a36Sopenharmony_ci	xfs_fsblock_t	sumbno;		/* summary block number */
94762306a36Sopenharmony_ci	uint8_t		*rsum_cache;	/* old summary cache */
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	sbp = &mp->m_sb;
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	if (!capable(CAP_SYS_ADMIN))
95262306a36Sopenharmony_ci		return -EPERM;
95362306a36Sopenharmony_ci
95462306a36Sopenharmony_ci	/* Needs to have been mounted with an rt device. */
95562306a36Sopenharmony_ci	if (!XFS_IS_REALTIME_MOUNT(mp))
95662306a36Sopenharmony_ci		return -EINVAL;
95762306a36Sopenharmony_ci	/*
95862306a36Sopenharmony_ci	 * Mount should fail if the rt bitmap/summary files don't load, but
95962306a36Sopenharmony_ci	 * we'll check anyway.
96062306a36Sopenharmony_ci	 */
96162306a36Sopenharmony_ci	if (!mp->m_rbmip || !mp->m_rsumip)
96262306a36Sopenharmony_ci		return -EINVAL;
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	/* Shrink not supported. */
96562306a36Sopenharmony_ci	if (in->newblocks <= sbp->sb_rblocks)
96662306a36Sopenharmony_ci		return -EINVAL;
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	/* Can only change rt extent size when adding rt volume. */
96962306a36Sopenharmony_ci	if (sbp->sb_rblocks > 0 && in->extsize != sbp->sb_rextsize)
97062306a36Sopenharmony_ci		return -EINVAL;
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_ci	/* Range check the extent size. */
97362306a36Sopenharmony_ci	if (XFS_FSB_TO_B(mp, in->extsize) > XFS_MAX_RTEXTSIZE ||
97462306a36Sopenharmony_ci	    XFS_FSB_TO_B(mp, in->extsize) < XFS_MIN_RTEXTSIZE)
97562306a36Sopenharmony_ci		return -EINVAL;
97662306a36Sopenharmony_ci
97762306a36Sopenharmony_ci	/* Unsupported realtime features. */
97862306a36Sopenharmony_ci	if (xfs_has_rmapbt(mp) || xfs_has_reflink(mp) || xfs_has_quota(mp))
97962306a36Sopenharmony_ci		return -EOPNOTSUPP;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	nrblocks = in->newblocks;
98262306a36Sopenharmony_ci	error = xfs_sb_validate_fsb_count(sbp, nrblocks);
98362306a36Sopenharmony_ci	if (error)
98462306a36Sopenharmony_ci		return error;
98562306a36Sopenharmony_ci	/*
98662306a36Sopenharmony_ci	 * Read in the last block of the device, make sure it exists.
98762306a36Sopenharmony_ci	 */
98862306a36Sopenharmony_ci	error = xfs_buf_read_uncached(mp->m_rtdev_targp,
98962306a36Sopenharmony_ci				XFS_FSB_TO_BB(mp, nrblocks - 1),
99062306a36Sopenharmony_ci				XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
99162306a36Sopenharmony_ci	if (error)
99262306a36Sopenharmony_ci		return error;
99362306a36Sopenharmony_ci	xfs_buf_relse(bp);
99462306a36Sopenharmony_ci
99562306a36Sopenharmony_ci	/*
99662306a36Sopenharmony_ci	 * Calculate new parameters.  These are the final values to be reached.
99762306a36Sopenharmony_ci	 */
99862306a36Sopenharmony_ci	nrextents = nrblocks;
99962306a36Sopenharmony_ci	do_div(nrextents, in->extsize);
100062306a36Sopenharmony_ci	nrbmblocks = howmany_64(nrextents, NBBY * sbp->sb_blocksize);
100162306a36Sopenharmony_ci	nrextslog = xfs_highbit32(nrextents);
100262306a36Sopenharmony_ci	nrsumlevels = nrextslog + 1;
100362306a36Sopenharmony_ci	nrsumsize = (uint)sizeof(xfs_suminfo_t) * nrsumlevels * nrbmblocks;
100462306a36Sopenharmony_ci	nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
100562306a36Sopenharmony_ci	nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
100662306a36Sopenharmony_ci	/*
100762306a36Sopenharmony_ci	 * New summary size can't be more than half the size of
100862306a36Sopenharmony_ci	 * the log.  This prevents us from getting a log overflow,
100962306a36Sopenharmony_ci	 * since we'll log basically the whole summary file at once.
101062306a36Sopenharmony_ci	 */
101162306a36Sopenharmony_ci	if (nrsumblocks > (mp->m_sb.sb_logblocks >> 1))
101262306a36Sopenharmony_ci		return -EINVAL;
101362306a36Sopenharmony_ci	/*
101462306a36Sopenharmony_ci	 * Get the old block counts for bitmap and summary inodes.
101562306a36Sopenharmony_ci	 * These can't change since other growfs callers are locked out.
101662306a36Sopenharmony_ci	 */
101762306a36Sopenharmony_ci	rbmblocks = XFS_B_TO_FSB(mp, mp->m_rbmip->i_disk_size);
101862306a36Sopenharmony_ci	rsumblocks = XFS_B_TO_FSB(mp, mp->m_rsumip->i_disk_size);
101962306a36Sopenharmony_ci	/*
102062306a36Sopenharmony_ci	 * Allocate space to the bitmap and summary files, as necessary.
102162306a36Sopenharmony_ci	 */
102262306a36Sopenharmony_ci	error = xfs_growfs_rt_alloc(mp, rbmblocks, nrbmblocks, mp->m_rbmip);
102362306a36Sopenharmony_ci	if (error)
102462306a36Sopenharmony_ci		return error;
102562306a36Sopenharmony_ci	error = xfs_growfs_rt_alloc(mp, rsumblocks, nrsumblocks, mp->m_rsumip);
102662306a36Sopenharmony_ci	if (error)
102762306a36Sopenharmony_ci		return error;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	rsum_cache = mp->m_rsum_cache;
103062306a36Sopenharmony_ci	if (nrbmblocks != sbp->sb_rbmblocks)
103162306a36Sopenharmony_ci		xfs_alloc_rsum_cache(mp, nrbmblocks);
103262306a36Sopenharmony_ci
103362306a36Sopenharmony_ci	/*
103462306a36Sopenharmony_ci	 * Allocate a new (fake) mount/sb.
103562306a36Sopenharmony_ci	 */
103662306a36Sopenharmony_ci	nmp = kmem_alloc(sizeof(*nmp), 0);
103762306a36Sopenharmony_ci	/*
103862306a36Sopenharmony_ci	 * Loop over the bitmap blocks.
103962306a36Sopenharmony_ci	 * We will do everything one bitmap block at a time.
104062306a36Sopenharmony_ci	 * Skip the current block if it is exactly full.
104162306a36Sopenharmony_ci	 * This also deals with the case where there were no rtextents before.
104262306a36Sopenharmony_ci	 */
104362306a36Sopenharmony_ci	for (bmbno = sbp->sb_rbmblocks -
104462306a36Sopenharmony_ci		     ((sbp->sb_rextents & ((1 << mp->m_blkbit_log) - 1)) != 0);
104562306a36Sopenharmony_ci	     bmbno < nrbmblocks;
104662306a36Sopenharmony_ci	     bmbno++) {
104762306a36Sopenharmony_ci		struct xfs_trans	*tp;
104862306a36Sopenharmony_ci		xfs_rfsblock_t		nrblocks_step;
104962306a36Sopenharmony_ci
105062306a36Sopenharmony_ci		*nmp = *mp;
105162306a36Sopenharmony_ci		nsbp = &nmp->m_sb;
105262306a36Sopenharmony_ci		/*
105362306a36Sopenharmony_ci		 * Calculate new sb and mount fields for this round.
105462306a36Sopenharmony_ci		 */
105562306a36Sopenharmony_ci		nsbp->sb_rextsize = in->extsize;
105662306a36Sopenharmony_ci		nsbp->sb_rbmblocks = bmbno + 1;
105762306a36Sopenharmony_ci		nrblocks_step = (bmbno + 1) * NBBY * nsbp->sb_blocksize *
105862306a36Sopenharmony_ci				nsbp->sb_rextsize;
105962306a36Sopenharmony_ci		nsbp->sb_rblocks = min(nrblocks, nrblocks_step);
106062306a36Sopenharmony_ci		nsbp->sb_rextents = nsbp->sb_rblocks;
106162306a36Sopenharmony_ci		do_div(nsbp->sb_rextents, nsbp->sb_rextsize);
106262306a36Sopenharmony_ci		ASSERT(nsbp->sb_rextents != 0);
106362306a36Sopenharmony_ci		nsbp->sb_rextslog = xfs_highbit32(nsbp->sb_rextents);
106462306a36Sopenharmony_ci		nrsumlevels = nmp->m_rsumlevels = nsbp->sb_rextslog + 1;
106562306a36Sopenharmony_ci		nrsumsize =
106662306a36Sopenharmony_ci			(uint)sizeof(xfs_suminfo_t) * nrsumlevels *
106762306a36Sopenharmony_ci			nsbp->sb_rbmblocks;
106862306a36Sopenharmony_ci		nrsumblocks = XFS_B_TO_FSB(mp, nrsumsize);
106962306a36Sopenharmony_ci		nmp->m_rsumsize = nrsumsize = XFS_FSB_TO_B(mp, nrsumblocks);
107062306a36Sopenharmony_ci		/*
107162306a36Sopenharmony_ci		 * Start a transaction, get the log reservation.
107262306a36Sopenharmony_ci		 */
107362306a36Sopenharmony_ci		error = xfs_trans_alloc(mp, &M_RES(mp)->tr_growrtfree, 0, 0, 0,
107462306a36Sopenharmony_ci				&tp);
107562306a36Sopenharmony_ci		if (error)
107662306a36Sopenharmony_ci			break;
107762306a36Sopenharmony_ci		/*
107862306a36Sopenharmony_ci		 * Lock out other callers by grabbing the bitmap inode lock.
107962306a36Sopenharmony_ci		 */
108062306a36Sopenharmony_ci		xfs_ilock(mp->m_rbmip, XFS_ILOCK_EXCL | XFS_ILOCK_RTBITMAP);
108162306a36Sopenharmony_ci		xfs_trans_ijoin(tp, mp->m_rbmip, XFS_ILOCK_EXCL);
108262306a36Sopenharmony_ci		/*
108362306a36Sopenharmony_ci		 * Update the bitmap inode's size ondisk and incore.  We need
108462306a36Sopenharmony_ci		 * to update the incore size so that inode inactivation won't
108562306a36Sopenharmony_ci		 * punch what it thinks are "posteof" blocks.
108662306a36Sopenharmony_ci		 */
108762306a36Sopenharmony_ci		mp->m_rbmip->i_disk_size =
108862306a36Sopenharmony_ci			nsbp->sb_rbmblocks * nsbp->sb_blocksize;
108962306a36Sopenharmony_ci		i_size_write(VFS_I(mp->m_rbmip), mp->m_rbmip->i_disk_size);
109062306a36Sopenharmony_ci		xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
109162306a36Sopenharmony_ci		/*
109262306a36Sopenharmony_ci		 * Get the summary inode into the transaction.
109362306a36Sopenharmony_ci		 */
109462306a36Sopenharmony_ci		xfs_ilock(mp->m_rsumip, XFS_ILOCK_EXCL | XFS_ILOCK_RTSUM);
109562306a36Sopenharmony_ci		xfs_trans_ijoin(tp, mp->m_rsumip, XFS_ILOCK_EXCL);
109662306a36Sopenharmony_ci		/*
109762306a36Sopenharmony_ci		 * Update the summary inode's size.  We need to update the
109862306a36Sopenharmony_ci		 * incore size so that inode inactivation won't punch what it
109962306a36Sopenharmony_ci		 * thinks are "posteof" blocks.
110062306a36Sopenharmony_ci		 */
110162306a36Sopenharmony_ci		mp->m_rsumip->i_disk_size = nmp->m_rsumsize;
110262306a36Sopenharmony_ci		i_size_write(VFS_I(mp->m_rsumip), mp->m_rsumip->i_disk_size);
110362306a36Sopenharmony_ci		xfs_trans_log_inode(tp, mp->m_rsumip, XFS_ILOG_CORE);
110462306a36Sopenharmony_ci		/*
110562306a36Sopenharmony_ci		 * Copy summary data from old to new sizes.
110662306a36Sopenharmony_ci		 * Do this when the real size (not block-aligned) changes.
110762306a36Sopenharmony_ci		 */
110862306a36Sopenharmony_ci		if (sbp->sb_rbmblocks != nsbp->sb_rbmblocks ||
110962306a36Sopenharmony_ci		    mp->m_rsumlevels != nmp->m_rsumlevels) {
111062306a36Sopenharmony_ci			error = xfs_rtcopy_summary(mp, nmp, tp);
111162306a36Sopenharmony_ci			if (error)
111262306a36Sopenharmony_ci				goto error_cancel;
111362306a36Sopenharmony_ci		}
111462306a36Sopenharmony_ci		/*
111562306a36Sopenharmony_ci		 * Update superblock fields.
111662306a36Sopenharmony_ci		 */
111762306a36Sopenharmony_ci		if (nsbp->sb_rextsize != sbp->sb_rextsize)
111862306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSIZE,
111962306a36Sopenharmony_ci				nsbp->sb_rextsize - sbp->sb_rextsize);
112062306a36Sopenharmony_ci		if (nsbp->sb_rbmblocks != sbp->sb_rbmblocks)
112162306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBMBLOCKS,
112262306a36Sopenharmony_ci				nsbp->sb_rbmblocks - sbp->sb_rbmblocks);
112362306a36Sopenharmony_ci		if (nsbp->sb_rblocks != sbp->sb_rblocks)
112462306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RBLOCKS,
112562306a36Sopenharmony_ci				nsbp->sb_rblocks - sbp->sb_rblocks);
112662306a36Sopenharmony_ci		if (nsbp->sb_rextents != sbp->sb_rextents)
112762306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTENTS,
112862306a36Sopenharmony_ci				nsbp->sb_rextents - sbp->sb_rextents);
112962306a36Sopenharmony_ci		if (nsbp->sb_rextslog != sbp->sb_rextslog)
113062306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_REXTSLOG,
113162306a36Sopenharmony_ci				nsbp->sb_rextslog - sbp->sb_rextslog);
113262306a36Sopenharmony_ci		/*
113362306a36Sopenharmony_ci		 * Free new extent.
113462306a36Sopenharmony_ci		 */
113562306a36Sopenharmony_ci		bp = NULL;
113662306a36Sopenharmony_ci		error = xfs_rtfree_range(nmp, tp, sbp->sb_rextents,
113762306a36Sopenharmony_ci			nsbp->sb_rextents - sbp->sb_rextents, &bp, &sumbno);
113862306a36Sopenharmony_ci		if (error) {
113962306a36Sopenharmony_cierror_cancel:
114062306a36Sopenharmony_ci			xfs_trans_cancel(tp);
114162306a36Sopenharmony_ci			break;
114262306a36Sopenharmony_ci		}
114362306a36Sopenharmony_ci		/*
114462306a36Sopenharmony_ci		 * Mark more blocks free in the superblock.
114562306a36Sopenharmony_ci		 */
114662306a36Sopenharmony_ci		xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS,
114762306a36Sopenharmony_ci			nsbp->sb_rextents - sbp->sb_rextents);
114862306a36Sopenharmony_ci		/*
114962306a36Sopenharmony_ci		 * Update mp values into the real mp structure.
115062306a36Sopenharmony_ci		 */
115162306a36Sopenharmony_ci		mp->m_rsumlevels = nrsumlevels;
115262306a36Sopenharmony_ci		mp->m_rsumsize = nrsumsize;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci		error = xfs_trans_commit(tp);
115562306a36Sopenharmony_ci		if (error)
115662306a36Sopenharmony_ci			break;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci		/* Ensure the mount RT feature flag is now set. */
115962306a36Sopenharmony_ci		mp->m_features |= XFS_FEAT_REALTIME;
116062306a36Sopenharmony_ci	}
116162306a36Sopenharmony_ci	if (error)
116262306a36Sopenharmony_ci		goto out_free;
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ci	/* Update secondary superblocks now the physical grow has completed */
116562306a36Sopenharmony_ci	error = xfs_update_secondary_sbs(mp);
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ciout_free:
116862306a36Sopenharmony_ci	/*
116962306a36Sopenharmony_ci	 * Free the fake mp structure.
117062306a36Sopenharmony_ci	 */
117162306a36Sopenharmony_ci	kmem_free(nmp);
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	/*
117462306a36Sopenharmony_ci	 * If we had to allocate a new rsum_cache, we either need to free the
117562306a36Sopenharmony_ci	 * old one (if we succeeded) or free the new one and restore the old one
117662306a36Sopenharmony_ci	 * (if there was an error).
117762306a36Sopenharmony_ci	 */
117862306a36Sopenharmony_ci	if (rsum_cache != mp->m_rsum_cache) {
117962306a36Sopenharmony_ci		if (error) {
118062306a36Sopenharmony_ci			kmem_free(mp->m_rsum_cache);
118162306a36Sopenharmony_ci			mp->m_rsum_cache = rsum_cache;
118262306a36Sopenharmony_ci		} else {
118362306a36Sopenharmony_ci			kmem_free(rsum_cache);
118462306a36Sopenharmony_ci		}
118562306a36Sopenharmony_ci	}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	return error;
118862306a36Sopenharmony_ci}
118962306a36Sopenharmony_ci
119062306a36Sopenharmony_ci/*
119162306a36Sopenharmony_ci * Allocate an extent in the realtime subvolume, with the usual allocation
119262306a36Sopenharmony_ci * parameters.  The length units are all in realtime extents, as is the
119362306a36Sopenharmony_ci * result block number.
119462306a36Sopenharmony_ci */
119562306a36Sopenharmony_ciint					/* error */
119662306a36Sopenharmony_cixfs_rtallocate_extent(
119762306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
119862306a36Sopenharmony_ci	xfs_rtblock_t	bno,		/* starting block number to allocate */
119962306a36Sopenharmony_ci	xfs_extlen_t	minlen,		/* minimum length to allocate */
120062306a36Sopenharmony_ci	xfs_extlen_t	maxlen,		/* maximum length to allocate */
120162306a36Sopenharmony_ci	xfs_extlen_t	*len,		/* out: actual length allocated */
120262306a36Sopenharmony_ci	int		wasdel,		/* was a delayed allocation extent */
120362306a36Sopenharmony_ci	xfs_extlen_t	prod,		/* extent product factor */
120462306a36Sopenharmony_ci	xfs_rtblock_t	*rtblock)	/* out: start block allocated */
120562306a36Sopenharmony_ci{
120662306a36Sopenharmony_ci	xfs_mount_t	*mp = tp->t_mountp;
120762306a36Sopenharmony_ci	int		error;		/* error value */
120862306a36Sopenharmony_ci	xfs_rtblock_t	r;		/* result allocated block */
120962306a36Sopenharmony_ci	xfs_fsblock_t	sb;		/* summary file block number */
121062306a36Sopenharmony_ci	struct xfs_buf	*sumbp;		/* summary file block buffer */
121162306a36Sopenharmony_ci
121262306a36Sopenharmony_ci	ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
121362306a36Sopenharmony_ci	ASSERT(minlen > 0 && minlen <= maxlen);
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	/*
121662306a36Sopenharmony_ci	 * If prod is set then figure out what to do to minlen and maxlen.
121762306a36Sopenharmony_ci	 */
121862306a36Sopenharmony_ci	if (prod > 1) {
121962306a36Sopenharmony_ci		xfs_extlen_t	i;
122062306a36Sopenharmony_ci
122162306a36Sopenharmony_ci		if ((i = maxlen % prod))
122262306a36Sopenharmony_ci			maxlen -= i;
122362306a36Sopenharmony_ci		if ((i = minlen % prod))
122462306a36Sopenharmony_ci			minlen += prod - i;
122562306a36Sopenharmony_ci		if (maxlen < minlen) {
122662306a36Sopenharmony_ci			*rtblock = NULLRTBLOCK;
122762306a36Sopenharmony_ci			return 0;
122862306a36Sopenharmony_ci		}
122962306a36Sopenharmony_ci	}
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ciretry:
123262306a36Sopenharmony_ci	sumbp = NULL;
123362306a36Sopenharmony_ci	if (bno == 0) {
123462306a36Sopenharmony_ci		error = xfs_rtallocate_extent_size(mp, tp, minlen, maxlen, len,
123562306a36Sopenharmony_ci				&sumbp,	&sb, prod, &r);
123662306a36Sopenharmony_ci	} else {
123762306a36Sopenharmony_ci		error = xfs_rtallocate_extent_near(mp, tp, bno, minlen, maxlen,
123862306a36Sopenharmony_ci				len, &sumbp, &sb, prod, &r);
123962306a36Sopenharmony_ci	}
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	if (error)
124262306a36Sopenharmony_ci		return error;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci	/*
124562306a36Sopenharmony_ci	 * If it worked, update the superblock.
124662306a36Sopenharmony_ci	 */
124762306a36Sopenharmony_ci	if (r != NULLRTBLOCK) {
124862306a36Sopenharmony_ci		long	slen = (long)*len;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci		ASSERT(*len >= minlen && *len <= maxlen);
125162306a36Sopenharmony_ci		if (wasdel)
125262306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_RES_FREXTENTS, -slen);
125362306a36Sopenharmony_ci		else
125462306a36Sopenharmony_ci			xfs_trans_mod_sb(tp, XFS_TRANS_SB_FREXTENTS, -slen);
125562306a36Sopenharmony_ci	} else if (prod > 1) {
125662306a36Sopenharmony_ci		prod = 1;
125762306a36Sopenharmony_ci		goto retry;
125862306a36Sopenharmony_ci	}
125962306a36Sopenharmony_ci
126062306a36Sopenharmony_ci	*rtblock = r;
126162306a36Sopenharmony_ci	return 0;
126262306a36Sopenharmony_ci}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci/*
126562306a36Sopenharmony_ci * Initialize realtime fields in the mount structure.
126662306a36Sopenharmony_ci */
126762306a36Sopenharmony_ciint				/* error */
126862306a36Sopenharmony_cixfs_rtmount_init(
126962306a36Sopenharmony_ci	struct xfs_mount	*mp)	/* file system mount structure */
127062306a36Sopenharmony_ci{
127162306a36Sopenharmony_ci	struct xfs_buf		*bp;	/* buffer for last block of subvolume */
127262306a36Sopenharmony_ci	struct xfs_sb		*sbp;	/* filesystem superblock copy in mount */
127362306a36Sopenharmony_ci	xfs_daddr_t		d;	/* address of last block of subvolume */
127462306a36Sopenharmony_ci	int			error;
127562306a36Sopenharmony_ci
127662306a36Sopenharmony_ci	sbp = &mp->m_sb;
127762306a36Sopenharmony_ci	if (sbp->sb_rblocks == 0)
127862306a36Sopenharmony_ci		return 0;
127962306a36Sopenharmony_ci	if (mp->m_rtdev_targp == NULL) {
128062306a36Sopenharmony_ci		xfs_warn(mp,
128162306a36Sopenharmony_ci	"Filesystem has a realtime volume, use rtdev=device option");
128262306a36Sopenharmony_ci		return -ENODEV;
128362306a36Sopenharmony_ci	}
128462306a36Sopenharmony_ci	mp->m_rsumlevels = sbp->sb_rextslog + 1;
128562306a36Sopenharmony_ci	mp->m_rsumsize =
128662306a36Sopenharmony_ci		(uint)sizeof(xfs_suminfo_t) * mp->m_rsumlevels *
128762306a36Sopenharmony_ci		sbp->sb_rbmblocks;
128862306a36Sopenharmony_ci	mp->m_rsumsize = roundup(mp->m_rsumsize, sbp->sb_blocksize);
128962306a36Sopenharmony_ci	mp->m_rbmip = mp->m_rsumip = NULL;
129062306a36Sopenharmony_ci	/*
129162306a36Sopenharmony_ci	 * Check that the realtime section is an ok size.
129262306a36Sopenharmony_ci	 */
129362306a36Sopenharmony_ci	d = (xfs_daddr_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_rblocks);
129462306a36Sopenharmony_ci	if (XFS_BB_TO_FSB(mp, d) != mp->m_sb.sb_rblocks) {
129562306a36Sopenharmony_ci		xfs_warn(mp, "realtime mount -- %llu != %llu",
129662306a36Sopenharmony_ci			(unsigned long long) XFS_BB_TO_FSB(mp, d),
129762306a36Sopenharmony_ci			(unsigned long long) mp->m_sb.sb_rblocks);
129862306a36Sopenharmony_ci		return -EFBIG;
129962306a36Sopenharmony_ci	}
130062306a36Sopenharmony_ci	error = xfs_buf_read_uncached(mp->m_rtdev_targp,
130162306a36Sopenharmony_ci					d - XFS_FSB_TO_BB(mp, 1),
130262306a36Sopenharmony_ci					XFS_FSB_TO_BB(mp, 1), 0, &bp, NULL);
130362306a36Sopenharmony_ci	if (error) {
130462306a36Sopenharmony_ci		xfs_warn(mp, "realtime device size check failed");
130562306a36Sopenharmony_ci		return error;
130662306a36Sopenharmony_ci	}
130762306a36Sopenharmony_ci	xfs_buf_relse(bp);
130862306a36Sopenharmony_ci	return 0;
130962306a36Sopenharmony_ci}
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_cistatic int
131262306a36Sopenharmony_cixfs_rtalloc_count_frextent(
131362306a36Sopenharmony_ci	struct xfs_mount		*mp,
131462306a36Sopenharmony_ci	struct xfs_trans		*tp,
131562306a36Sopenharmony_ci	const struct xfs_rtalloc_rec	*rec,
131662306a36Sopenharmony_ci	void				*priv)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	uint64_t			*valp = priv;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	*valp += rec->ar_extcount;
132162306a36Sopenharmony_ci	return 0;
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci/*
132562306a36Sopenharmony_ci * Reinitialize the number of free realtime extents from the realtime bitmap.
132662306a36Sopenharmony_ci * Callers must ensure that there is no other activity in the filesystem.
132762306a36Sopenharmony_ci */
132862306a36Sopenharmony_ciint
132962306a36Sopenharmony_cixfs_rtalloc_reinit_frextents(
133062306a36Sopenharmony_ci	struct xfs_mount	*mp)
133162306a36Sopenharmony_ci{
133262306a36Sopenharmony_ci	uint64_t		val = 0;
133362306a36Sopenharmony_ci	int			error;
133462306a36Sopenharmony_ci
133562306a36Sopenharmony_ci	xfs_ilock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
133662306a36Sopenharmony_ci	error = xfs_rtalloc_query_all(mp, NULL, xfs_rtalloc_count_frextent,
133762306a36Sopenharmony_ci			&val);
133862306a36Sopenharmony_ci	xfs_iunlock(mp->m_rbmip, XFS_ILOCK_SHARED | XFS_ILOCK_RTBITMAP);
133962306a36Sopenharmony_ci	if (error)
134062306a36Sopenharmony_ci		return error;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	spin_lock(&mp->m_sb_lock);
134362306a36Sopenharmony_ci	mp->m_sb.sb_frextents = val;
134462306a36Sopenharmony_ci	spin_unlock(&mp->m_sb_lock);
134562306a36Sopenharmony_ci	percpu_counter_set(&mp->m_frextents, mp->m_sb.sb_frextents);
134662306a36Sopenharmony_ci	return 0;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ci
134962306a36Sopenharmony_ci/*
135062306a36Sopenharmony_ci * Read in the bmbt of an rt metadata inode so that we never have to load them
135162306a36Sopenharmony_ci * at runtime.  This enables the use of shared ILOCKs for rtbitmap scans.  Use
135262306a36Sopenharmony_ci * an empty transaction to avoid deadlocking on loops in the bmbt.
135362306a36Sopenharmony_ci */
135462306a36Sopenharmony_cistatic inline int
135562306a36Sopenharmony_cixfs_rtmount_iread_extents(
135662306a36Sopenharmony_ci	struct xfs_inode	*ip,
135762306a36Sopenharmony_ci	unsigned int		lock_class)
135862306a36Sopenharmony_ci{
135962306a36Sopenharmony_ci	struct xfs_trans	*tp;
136062306a36Sopenharmony_ci	int			error;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	error = xfs_trans_alloc_empty(ip->i_mount, &tp);
136362306a36Sopenharmony_ci	if (error)
136462306a36Sopenharmony_ci		return error;
136562306a36Sopenharmony_ci
136662306a36Sopenharmony_ci	xfs_ilock(ip, XFS_ILOCK_EXCL | lock_class);
136762306a36Sopenharmony_ci
136862306a36Sopenharmony_ci	error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);
136962306a36Sopenharmony_ci	if (error)
137062306a36Sopenharmony_ci		goto out_unlock;
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	if (xfs_inode_has_attr_fork(ip)) {
137362306a36Sopenharmony_ci		error = xfs_iread_extents(tp, ip, XFS_ATTR_FORK);
137462306a36Sopenharmony_ci		if (error)
137562306a36Sopenharmony_ci			goto out_unlock;
137662306a36Sopenharmony_ci	}
137762306a36Sopenharmony_ci
137862306a36Sopenharmony_ciout_unlock:
137962306a36Sopenharmony_ci	xfs_iunlock(ip, XFS_ILOCK_EXCL | lock_class);
138062306a36Sopenharmony_ci	xfs_trans_cancel(tp);
138162306a36Sopenharmony_ci	return error;
138262306a36Sopenharmony_ci}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci/*
138562306a36Sopenharmony_ci * Get the bitmap and summary inodes and the summary cache into the mount
138662306a36Sopenharmony_ci * structure at mount time.
138762306a36Sopenharmony_ci */
138862306a36Sopenharmony_ciint					/* error */
138962306a36Sopenharmony_cixfs_rtmount_inodes(
139062306a36Sopenharmony_ci	xfs_mount_t	*mp)		/* file system mount structure */
139162306a36Sopenharmony_ci{
139262306a36Sopenharmony_ci	int		error;		/* error return value */
139362306a36Sopenharmony_ci	xfs_sb_t	*sbp;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	sbp = &mp->m_sb;
139662306a36Sopenharmony_ci	error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip);
139762306a36Sopenharmony_ci	if (error)
139862306a36Sopenharmony_ci		return error;
139962306a36Sopenharmony_ci	ASSERT(mp->m_rbmip != NULL);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci	error = xfs_rtmount_iread_extents(mp->m_rbmip, XFS_ILOCK_RTBITMAP);
140262306a36Sopenharmony_ci	if (error)
140362306a36Sopenharmony_ci		goto out_rele_bitmap;
140462306a36Sopenharmony_ci
140562306a36Sopenharmony_ci	error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip);
140662306a36Sopenharmony_ci	if (error)
140762306a36Sopenharmony_ci		goto out_rele_bitmap;
140862306a36Sopenharmony_ci	ASSERT(mp->m_rsumip != NULL);
140962306a36Sopenharmony_ci
141062306a36Sopenharmony_ci	error = xfs_rtmount_iread_extents(mp->m_rsumip, XFS_ILOCK_RTSUM);
141162306a36Sopenharmony_ci	if (error)
141262306a36Sopenharmony_ci		goto out_rele_summary;
141362306a36Sopenharmony_ci
141462306a36Sopenharmony_ci	xfs_alloc_rsum_cache(mp, sbp->sb_rbmblocks);
141562306a36Sopenharmony_ci	return 0;
141662306a36Sopenharmony_ci
141762306a36Sopenharmony_ciout_rele_summary:
141862306a36Sopenharmony_ci	xfs_irele(mp->m_rsumip);
141962306a36Sopenharmony_ciout_rele_bitmap:
142062306a36Sopenharmony_ci	xfs_irele(mp->m_rbmip);
142162306a36Sopenharmony_ci	return error;
142262306a36Sopenharmony_ci}
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_civoid
142562306a36Sopenharmony_cixfs_rtunmount_inodes(
142662306a36Sopenharmony_ci	struct xfs_mount	*mp)
142762306a36Sopenharmony_ci{
142862306a36Sopenharmony_ci	kmem_free(mp->m_rsum_cache);
142962306a36Sopenharmony_ci	if (mp->m_rbmip)
143062306a36Sopenharmony_ci		xfs_irele(mp->m_rbmip);
143162306a36Sopenharmony_ci	if (mp->m_rsumip)
143262306a36Sopenharmony_ci		xfs_irele(mp->m_rsumip);
143362306a36Sopenharmony_ci}
143462306a36Sopenharmony_ci
143562306a36Sopenharmony_ci/*
143662306a36Sopenharmony_ci * Pick an extent for allocation at the start of a new realtime file.
143762306a36Sopenharmony_ci * Use the sequence number stored in the atime field of the bitmap inode.
143862306a36Sopenharmony_ci * Translate this to a fraction of the rtextents, and return the product
143962306a36Sopenharmony_ci * of rtextents and the fraction.
144062306a36Sopenharmony_ci * The fraction sequence is 0, 1/2, 1/4, 3/4, 1/8, ..., 7/8, 1/16, ...
144162306a36Sopenharmony_ci */
144262306a36Sopenharmony_ciint					/* error */
144362306a36Sopenharmony_cixfs_rtpick_extent(
144462306a36Sopenharmony_ci	xfs_mount_t	*mp,		/* file system mount point */
144562306a36Sopenharmony_ci	xfs_trans_t	*tp,		/* transaction pointer */
144662306a36Sopenharmony_ci	xfs_extlen_t	len,		/* allocation length (rtextents) */
144762306a36Sopenharmony_ci	xfs_rtblock_t	*pick)		/* result rt extent */
144862306a36Sopenharmony_ci{
144962306a36Sopenharmony_ci	xfs_rtblock_t	b;		/* result block */
145062306a36Sopenharmony_ci	int		log2;		/* log of sequence number */
145162306a36Sopenharmony_ci	uint64_t	resid;		/* residual after log removed */
145262306a36Sopenharmony_ci	uint64_t	seq;		/* sequence number of file creation */
145362306a36Sopenharmony_ci	uint64_t	*seqp;		/* pointer to seqno in inode */
145462306a36Sopenharmony_ci
145562306a36Sopenharmony_ci	ASSERT(xfs_isilocked(mp->m_rbmip, XFS_ILOCK_EXCL));
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	seqp = (uint64_t *)&VFS_I(mp->m_rbmip)->i_atime;
145862306a36Sopenharmony_ci	if (!(mp->m_rbmip->i_diflags & XFS_DIFLAG_NEWRTBM)) {
145962306a36Sopenharmony_ci		mp->m_rbmip->i_diflags |= XFS_DIFLAG_NEWRTBM;
146062306a36Sopenharmony_ci		*seqp = 0;
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci	seq = *seqp;
146362306a36Sopenharmony_ci	if ((log2 = xfs_highbit64(seq)) == -1)
146462306a36Sopenharmony_ci		b = 0;
146562306a36Sopenharmony_ci	else {
146662306a36Sopenharmony_ci		resid = seq - (1ULL << log2);
146762306a36Sopenharmony_ci		b = (mp->m_sb.sb_rextents * ((resid << 1) + 1ULL)) >>
146862306a36Sopenharmony_ci		    (log2 + 1);
146962306a36Sopenharmony_ci		if (b >= mp->m_sb.sb_rextents)
147062306a36Sopenharmony_ci			div64_u64_rem(b, mp->m_sb.sb_rextents, &b);
147162306a36Sopenharmony_ci		if (b + len > mp->m_sb.sb_rextents)
147262306a36Sopenharmony_ci			b = mp->m_sb.sb_rextents - len;
147362306a36Sopenharmony_ci	}
147462306a36Sopenharmony_ci	*seqp = seq + 1;
147562306a36Sopenharmony_ci	xfs_trans_log_inode(tp, mp->m_rbmip, XFS_ILOG_CORE);
147662306a36Sopenharmony_ci	*pick = b;
147762306a36Sopenharmony_ci	return 0;
147862306a36Sopenharmony_ci}
1479