2223 lines · 55.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0/* * Copyright (c) 2000-2005 Silicon Graphics, Inc. * All Rights Reserved. */#include "xfs_platform.h"#include "xfs_fs.h"#include "xfs_shared.h"#include "xfs_format.h"#include "xfs_log_format.h"#include "xfs_trans_resv.h"#include "xfs_bit.h"#include "xfs_mount.h"#include "xfs_inode.h"#include "xfs_alloc.h"#include "xfs_bmap.h"#include "xfs_bmap_btree.h"#include "xfs_bmap_util.h"#include "xfs_trans.h"#include "xfs_trans_space.h"#include "xfs_icache.h"#include "xfs_rtalloc.h"#include "xfs_sb.h"#include "xfs_rtbitmap.h"#include "xfs_rtrmap_btree.h"#include "xfs_quota.h"#include "xfs_log_priv.h"#include "xfs_health.h"#include "xfs_da_format.h"#include "xfs_metafile.h"#include "xfs_rtgroup.h"#include "xfs_error.h"#include "xfs_trace.h"#include "xfs_rtrefcount_btree.h"#include "xfs_reflink.h"#include "xfs_zone_alloc.h" /* * Return whether there are any free extents in the size range given * by low and high, for the bitmap block bbno. */STATIC intxfs_rtany_summary(	struct xfs_rtalloc_args	*args,	int			low,	/* low log2 extent size */	int			high,	/* high log2 extent size */	xfs_fileoff_t		bbno,	/* bitmap block number */	int			*maxlog) /* out: max log2 extent size free */{	uint8_t			*rsum_cache = args->rtg->rtg_rsum_cache;	int			error;	int			log;	/* loop counter, log2 of ext. size */	xfs_suminfo_t		sum;	/* summary data */ 	/* There are no extents at levels >= rsum_cache[bbno]. */	if (rsum_cache) {		high = min(high, rsum_cache[bbno] - 1);		if (low > high) {			*maxlog = -1;			return 0;		}	} 	/*	 * Loop over logs of extent sizes.	 */	for (log = high; log >= low; log--) {		/*		 * Get one summary datum.		 */		error = xfs_rtget_summary(args, log, bbno, &sum);		if (error) {			return error;		}		/*		 * If there are any, return success.		 */		if (sum) {			*maxlog = log;			goto out;		}	}	/*	 * Found nothing, return failure.	 */	*maxlog = -1;out:	/* There were no extents at levels > log. */	if (rsum_cache && log + 1 < rsum_cache[bbno])		rsum_cache[bbno] = log + 1;	return 0;} /* * Copy and transform the summary file, given the old and new * parameters in the mount structures. */STATIC intxfs_rtcopy_summary(	struct xfs_rtalloc_args	*oargs,	struct xfs_rtalloc_args	*nargs){	xfs_fileoff_t		bbno;	/* bitmap block number */	int			error;	int			log;	/* summary level number (log length) */	xfs_suminfo_t		sum;	/* summary data */ 	for (log = oargs->mp->m_rsumlevels - 1; log >= 0; log--) {		for (bbno = oargs->mp->m_sb.sb_rbmblocks - 1;		     (xfs_srtblock_t)bbno >= 0;		     bbno--) {			error = xfs_rtget_summary(oargs, log, bbno, &sum);			if (error)				goto out;			if (XFS_IS_CORRUPT(oargs->mp, sum < 0)) {				error = -EFSCORRUPTED;				goto out;			}			if (sum == 0)				continue;			error = xfs_rtmodify_summary(oargs, log, bbno, -sum);			if (error)				goto out;			error = xfs_rtmodify_summary(nargs, log, bbno, sum);			if (error)				goto out;		}	}	error = 0;out:	xfs_rtbuf_cache_relse(oargs);	return error;}/* * Mark an extent specified by start and len allocated. * Updates all the summary information as well as the bitmap. */STATIC intxfs_rtallocate_range(	struct xfs_rtalloc_args	*args,	xfs_rtxnum_t		start,	/* start rtext to allocate */	xfs_rtxlen_t		len)	/* in/out: summary block number */{	struct xfs_mount	*mp = args->mp;	xfs_rtxnum_t		end;	/* end of the allocated rtext */	int			error;	xfs_rtxnum_t		postblock = 0; /* first rtext allocated > end */	xfs_rtxnum_t		preblock = 0; /* first rtext allocated < start */ 	end = start + len - 1;	/*	 * Assume we're allocating out of the middle of a free extent.	 * We need to find the beginning and end of the extent so we can	 * properly update the summary.	 */	error = xfs_rtfind_back(args, start, &preblock);	if (error)		return error; 	/*	 * Find the next allocated block (end of free extent).	 */	error = xfs_rtfind_forw(args, end, args->rtg->rtg_extents - 1,			&postblock);	if (error)		return error; 	/*	 * Decrement the summary information corresponding to the entire	 * (old) free extent.	 */	error = xfs_rtmodify_summary(args,			xfs_highbit64(postblock + 1 - preblock),			xfs_rtx_to_rbmblock(mp, preblock), -1);	if (error)		return error; 	/*	 * If there are blocks not being allocated at the front of the	 * old extent, add summary data for them to be free.	 */	if (preblock < start) {		error = xfs_rtmodify_summary(args,				xfs_highbit64(start - preblock),				xfs_rtx_to_rbmblock(mp, preblock), 1);		if (error)			return error;	} 	/*	 * If there are blocks not being allocated at the end of the	 * old extent, add summary data for them to be free.	 */	if (postblock > end) {		error = xfs_rtmodify_summary(args,				xfs_highbit64(postblock - end),				xfs_rtx_to_rbmblock(mp, end + 1), 1);		if (error)			return error;	} 	/*	 * Modify the bitmap to mark this extent allocated.	 */	return xfs_rtmodify_range(args, start, len, 0);} /* Reduce @rtxlen until it is a multiple of @prod. */static inline xfs_rtxlen_txfs_rtalloc_align_len(	xfs_rtxlen_t	rtxlen,	xfs_rtxlen_t	prod){	if (unlikely(prod > 1))		return rounddown(rtxlen, prod);	return rtxlen;} /* * Make sure we don't run off the end of the rt volume.  Be careful that * adjusting maxlen downwards doesn't cause us to fail the alignment checks. */static inline xfs_rtxlen_txfs_rtallocate_clamp_len(	struct xfs_rtgroup	*rtg,	xfs_rtxnum_t		startrtx,	xfs_rtxlen_t		rtxlen,	xfs_rtxlen_t		prod){	xfs_rtxlen_t		ret; 	ret = min(rtg->rtg_extents, startrtx + rtxlen) - startrtx;	return xfs_rtalloc_align_len(ret, prod);} /* * Attempt to allocate an extent minlen<=len<=maxlen starting from * bitmap block bbno.  If we don't get maxlen then use prod to trim * the length, if given.  Returns error; returns starting block in *rtx. * The lengths are all in rtextents. */STATIC intxfs_rtallocate_extent_block(	struct xfs_rtalloc_args	*args,	xfs_fileoff_t		bbno,	/* bitmap block number */	xfs_rtxlen_t		minlen,	/* minimum length to allocate */	xfs_rtxlen_t		maxlen,	/* maximum length to allocate */	xfs_rtxlen_t		*len,	/* out: actual length allocated */	xfs_rtxnum_t		*nextp,	/* out: next rtext to try */	xfs_rtxlen_t		prod,	/* extent product factor */	xfs_rtxnum_t		*rtx)	/* out: start rtext allocated */{	struct xfs_mount	*mp = args->mp;	xfs_rtxnum_t		besti = -1; /* best rtext found so far */	xfs_rtxnum_t		end;	/* last rtext in chunk */	xfs_rtxnum_t		i;	/* current rtext trying */	xfs_rtxnum_t		next;	/* next rtext to try */	xfs_rtxlen_t		scanlen; /* number of free rtx to look for */	xfs_rtxlen_t		bestlen = 0; /* best length found so far */	int			stat;	/* status from internal calls */	int			error; 	/*	 * Loop over all the extents starting in this bitmap block up to the	 * end of the rt volume, looking for one that's long enough.	 */	end = min(args->rtg->rtg_extents, xfs_rbmblock_to_rtx(mp, bbno + 1)) -		1;	for (i = xfs_rbmblock_to_rtx(mp, bbno); i <= end; i++) {		/* Make sure we don't scan off the end of the rt volume. */		scanlen = xfs_rtallocate_clamp_len(args->rtg, i, maxlen, prod);		if (scanlen < minlen)			break; 		/*		 * See if there's a free extent of scanlen starting at i.		 * If it's not so then next will contain the first non-free.		 */		error = xfs_rtcheck_range(args, i, scanlen, 1, &next, &stat);		if (error)			return error;		if (stat) {			/*			 * i to scanlen is all free, allocate and return that.			 */			*len = scanlen;			*rtx = i;			return 0;		} 		/*		 * In the case where we have a variable-sized allocation		 * request, figure out how big this free piece is,		 * and if it's big enough for the minimum, and the best		 * so far, remember it.		 */		if (minlen < maxlen) {			xfs_rtxnum_t	thislen;	/* this extent size */ 			thislen = next - i;			if (thislen >= minlen && thislen > bestlen) {				besti = i;				bestlen = thislen;			}		}		/*		 * If not done yet, find the start of the next free space.		 */		if (next >= end)			break;		error = xfs_rtfind_forw(args, next, end, &i);		if (error)			return error;	} 	/* Searched the whole thing & didn't find a maxlen free extent. */	if (besti == -1)		goto nospace; 	/*	 * Ensure bestlen is a multiple of prod, but don't return a too-short	 * extent.	 */	bestlen = xfs_rtalloc_align_len(bestlen, prod);	if (bestlen < minlen)		goto nospace; 	/*	 * Pick besti for bestlen & return that.	 */	*len = bestlen;	*rtx = besti;	return 0;nospace:	/* Allocation failed.  Set *nextp to the next block to try. */	*nextp = next;	return -ENOSPC;} /* * Allocate an extent of length minlen<=len<=maxlen, starting at block * bno.  If we don't get maxlen then use prod to trim the length, if given. * Returns error; returns starting block in *rtx. * The lengths are all in rtextents. */STATIC intxfs_rtallocate_extent_exact(	struct xfs_rtalloc_args	*args,	xfs_rtxnum_t		start,	/* starting rtext number to allocate */	xfs_rtxlen_t		minlen,	/* minimum length to allocate */	xfs_rtxlen_t		maxlen,	/* maximum length to allocate */	xfs_rtxlen_t		*len,	/* out: actual length allocated */	xfs_rtxlen_t		prod,	/* extent product factor */	xfs_rtxnum_t		*rtx)	/* out: start rtext allocated */{	xfs_rtxnum_t		next;	/* next rtext to try (dummy) */	xfs_rtxlen_t		alloclen; /* candidate length */	xfs_rtxlen_t		scanlen; /* number of free rtx to look for */	int			isfree;	/* extent is free */	int			error; 	ASSERT(minlen % prod == 0);	ASSERT(maxlen % prod == 0); 	/* Make sure we don't run off the end of the rt volume. */	scanlen = xfs_rtallocate_clamp_len(args->rtg, start, maxlen, prod);	if (scanlen < minlen)		return -ENOSPC; 	/* Check if the range in question (for scanlen) is free. */	error = xfs_rtcheck_range(args, start, scanlen, 1, &next, &isfree);	if (error)		return error; 	if (isfree) {		/* start to scanlen is all free; allocate it. */		*len = scanlen;		*rtx = start;		return 0;	} 	/*	 * If not, allocate what there is, if it's at least minlen.	 */	alloclen = next - start;	if (alloclen < minlen)		return -ENOSPC; 	/* Ensure alloclen is a multiple of prod. */	alloclen = xfs_rtalloc_align_len(alloclen, prod);	if (alloclen < minlen)		return -ENOSPC; 	*len = alloclen;	*rtx = start;	return 0;} /* * Allocate an extent of length minlen<=len<=maxlen, starting as near * to start as possible.  If we don't get maxlen then use prod to trim * the length, if given.  The lengths are all in rtextents. */STATIC intxfs_rtallocate_extent_near(	struct xfs_rtalloc_args	*args,	xfs_rtxnum_t		start,	/* starting rtext number to allocate */	xfs_rtxlen_t		minlen,	/* minimum length to allocate */	xfs_rtxlen_t		maxlen,	/* maximum length to allocate */	xfs_rtxlen_t		*len,	/* out: actual length allocated */	xfs_rtxlen_t		prod,	/* extent product factor */	xfs_rtxnum_t		*rtx)	/* out: start rtext allocated */{	struct xfs_mount	*mp = args->mp;	int			maxlog;	/* max useful extent from summary */	xfs_fileoff_t		bbno;	/* bitmap block number */	int			error;	int			i;	/* bitmap block offset (loop control) */	int			j;	/* secondary loop control */	int			log2len; /* log2 of minlen */	xfs_rtxnum_t		n;	/* next rtext to try */ 	ASSERT(minlen % prod == 0);	ASSERT(maxlen % prod == 0); 	/*	 * If the block number given is off the end, silently set it to the last	 * block.	 */	start = min(start, args->rtg->rtg_extents - 1); 	/*	 * Try the exact allocation first.	 */	error = xfs_rtallocate_extent_exact(args, start, minlen, maxlen, len,			prod, rtx);	if (error != -ENOSPC)		return error; 	bbno = xfs_rtx_to_rbmblock(mp, start);	i = 0;	j = -1;	ASSERT(minlen != 0);	log2len = xfs_highbit32(minlen);	/*	 * Loop over all bitmap blocks (bbno + i is current block).	 */	for (;;) {		/*		 * Get summary information of extents of all useful levels		 * starting in this bitmap block.		 */		error = xfs_rtany_summary(args, log2len, mp->m_rsumlevels - 1,				bbno + i, &maxlog);		if (error)			return error; 		/*		 * If there are any useful extents starting here, try		 * allocating one.		 */		if (maxlog >= 0) {			xfs_extlen_t maxavail =				min_t(xfs_rtblock_t, maxlen,				      (1ULL << (maxlog + 1)) - 1);			/*			 * On the positive side of the starting location.			 */			if (i >= 0) {				/*				 * Try to allocate an extent starting in				 * this block.				 */				error = xfs_rtallocate_extent_block(args,						bbno + i, minlen, maxavail, len,						&n, prod, rtx);				if (error != -ENOSPC)					return error;			}			/*			 * On the negative side of the starting location.			 */			else {		/* i < 0 */				int	maxblocks; 				/*				 * Loop backwards to find the end of the extent				 * we found in the realtime summary.				 *				 * maxblocks is the maximum possible number of				 * bitmap blocks from the start of the extent				 * to the end of the extent.				 */				if (maxlog == 0)					maxblocks = 0;				else if (maxlog < mp->m_blkbit_log)					maxblocks = 1;				else					maxblocks = 2 << (maxlog - mp->m_blkbit_log); 

Lines 1–500 of 2223.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t